From d8ab719c0890195cfce0fb6d4c76b3664d6f3a9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 10 Mar 2020 11:13:59 +0100 Subject: Fix double scaling of SVG icons on high DPI screens MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On a high-dpi screen and AA_UseHighDpiPixmaps set, QIcon will ask its engine for a scaled-up pixmap. When the icon has been created from a theme, the engine is a QIconLoaderEngine. For a SVG icon, that engine would recursively use QIcon to load the scaled-up pixmap, leading to double scale-up. Fix by bypassing the QIcon API in the SVG case, loading the SVG icon directly from the SVG icon engine. Done-with: Tor Arne Vestbø Fixes: QTBUG-73587 Fixes: QTBUG-75039 Change-Id: I7fba02b6454decb5fcbca9c5a092e75954261dfd Reviewed-by: Eirik Aavitsland Reviewed-by: Tor Arne Vestbø --- src/gui/image/qiconloader.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/gui') diff --git a/src/gui/image/qiconloader.cpp b/src/gui/image/qiconloader.cpp index 27c82bc09f..2f907a7709 100644 --- a/src/gui/image/qiconloader.cpp +++ b/src/gui/image/qiconloader.cpp @@ -797,8 +797,12 @@ QPixmap ScalableEntry::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State if (svgIcon.isNull()) svgIcon = QIcon(filename); - // Simply reuse svg icon engine - return svgIcon.pixmap(size, mode, state); + // Bypass QIcon API, as that will scale by device pixel ratio of the + // highest DPR screen since we're not passing on any QWindow. + if (QIconEngine *engine = svgIcon.data_ptr() ? svgIcon.data_ptr()->engine : nullptr) + return engine->pixmap(size, mode, state); + + return QPixmap(); } QPixmap QIconLoaderEngine::pixmap(const QSize &size, QIcon::Mode mode, -- cgit v1.2.3 From cfbe4818385b22128755e13cd8ab3c75182853c2 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 18 Mar 2020 12:23:22 +0100 Subject: QDrawHelper cleanups We don't need to handle solid SourceOver logic directly, this was already handled by getOperator and changed composition to Source. Also removes some dead code and changes an assert in unreachable code to Q_UNREACHABLE. Change-Id: I66a6c1248bd34e31096023f1acb20385099932c9 Reviewed-by: Eirik Aavitsland --- src/gui/painting/qdrawhelper.cpp | 10 ++++------ src/gui/painting/qdrawhelper_p.h | 2 +- src/gui/painting/qdrawhelper_x86_p.h | 3 --- 3 files changed, 5 insertions(+), 10 deletions(-) (limited to 'src/gui') diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 2d4045fe29..4b0cc2547c 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -4482,9 +4482,8 @@ static void blend_color_generic(int count, const QSpan *spans, void *userData) uint buffer[BufferSize]; Operator op = getOperator(data, nullptr, 0); const uint color = data->solidColor.toArgb32(); - bool solidFill = data->rasterBuffer->compositionMode == QPainter::CompositionMode_Source - || (data->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver && qAlpha(color) == 255); - QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp; + const bool solidFill = op.mode == QPainter::CompositionMode_Source; + const QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp; while (count--) { int x = spans->x; @@ -4552,9 +4551,8 @@ void blend_color_generic_rgb64(int count, const QSpan *spans, void *userData) alignas(8) QRgba64 buffer[BufferSize]; const QRgba64 color = data->solidColor; - bool solidFill = data->rasterBuffer->compositionMode == QPainter::CompositionMode_Source - || (data->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver && color.isOpaque()); - QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp; + const bool solidFill = op.mode == QPainter::CompositionMode_Source; + const QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp; while (count--) { int x = spans->x; diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index dd42b96d79..f1ad369906 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -601,7 +601,7 @@ public: FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP_PAD) break; default: - Q_ASSERT(false); + Q_UNREACHABLE(); } } }; diff --git a/src/gui/painting/qdrawhelper_x86_p.h b/src/gui/painting/qdrawhelper_x86_p.h index 5749d8c9fb..869abcc637 100644 --- a/src/gui/painting/qdrawhelper_x86_p.h +++ b/src/gui/painting/qdrawhelper_x86_p.h @@ -77,9 +77,6 @@ void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl, int w, int h, int const_alpha); -extern CompositionFunction qt_functionForMode_SSE2[]; -extern CompositionFunctionSolid qt_functionForModeSolid_SSE2[]; - void qt_memfill64_avx2(quint64 *dest, quint64 value, qsizetype count); void qt_memfill32_avx2(quint32 *dest, quint32 value, qsizetype count); #endif // __SSE2__ -- cgit v1.2.3 From 6c5b42b678b8e54cbb58f75d5d8abb50eff46dd9 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 13 Mar 2020 18:19:19 +0100 Subject: rhi: gl: Reduce state changes ...between setGraphicsPipeline() calls with different QRhiGraphicsPipeline instances within the same pass. Also adds similar logic for the GL_ARRAY_BUFFER (vertex buffers) as that is a hotspot as well. This is not intended to be a 100% avoiding any redundant call solution, but rather to take care of the most common hotspots, so that bad OpenGL implementations with a larger API call overhead will not cause us to regress compared to the direct OpenGL rendering path in Quick and Quick3D. What we have here reduces the number of GL calls in the view3d example by ~200 within one frame, which is a pretty good start. Task-number: QTBUG-78603 Change-Id: I6aeab9c1c43b148ea6ef05d0284990a996c7ba28 Reviewed-by: Andy Nichols --- src/gui/rhi/qrhigles2.cpp | 265 ++++++++++++++++++++++++++++++++------------ src/gui/rhi/qrhigles2_p_p.h | 87 ++++++++++++++- 2 files changed, 278 insertions(+), 74 deletions(-) (limited to 'src/gui') diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 3ba83464d2..52c5c70d3f 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -1193,7 +1193,18 @@ void QRhiGles2::beginExternal(QRhiCommandBuffer *cb) } QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb); + + if (cbD->recordingPass == QGles2CommandBuffer::ComputePass + && !cbD->computePassState.writtenResources.isEmpty()) + { + QGles2CommandBuffer::Command cmd; + cmd.cmd = QGles2CommandBuffer::Command::Barrier; + cmd.args.barrier.barriers = GL_ALL_BARRIER_BITS; + cbD->commands.append(cmd); + } + executeCommandBuffer(cbD); + cbD->resetCommands(); if (vao) @@ -1933,6 +1944,10 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb) GLenum indexType = GL_UNSIGNED_SHORT; quint32 indexStride = sizeof(quint16); quint32 indexOffset = 0; + GLuint currentArrayBuffer = 0; + static const int TRACKED_ATTRIB_COUNT = 16; + bool enabledAttribArrays[TRACKED_ATTRIB_COUNT]; + memset(enabledAttribArrays, 0, sizeof(enabledAttribArrays)); for (const QGles2CommandBuffer::Command &cmd : qAsConst(cbD->commands)) { switch (cmd.cmd) { @@ -1965,8 +1980,10 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb) { QGles2GraphicsPipeline *psD = QRHI_RES(QGles2GraphicsPipeline, cmd.args.stencilRef.ps); if (psD) { - f->glStencilFuncSeparate(GL_FRONT, toGlCompareOp(psD->m_stencilFront.compareOp), GLint(cmd.args.stencilRef.ref), psD->m_stencilReadMask); - f->glStencilFuncSeparate(GL_BACK, toGlCompareOp(psD->m_stencilBack.compareOp), GLint(cmd.args.stencilRef.ref), psD->m_stencilReadMask); + const GLint ref = GLint(cmd.args.stencilRef.ref); + f->glStencilFuncSeparate(GL_FRONT, toGlCompareOp(psD->m_stencilFront.compareOp), ref, psD->m_stencilReadMask); + f->glStencilFuncSeparate(GL_BACK, toGlCompareOp(psD->m_stencilBack.compareOp), ref, psD->m_stencilReadMask); + cbD->graphicsPassState.dynamic.stencilRef = ref; } else { qWarning("No graphics pipeline active for setStencilRef; ignored"); } @@ -1983,8 +2000,11 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb) if (bindingIdx != cmd.args.bindVertexBuffer.binding) continue; - // we do not support more than one vertex buffer - f->glBindBuffer(GL_ARRAY_BUFFER, cmd.args.bindVertexBuffer.buffer); + if (cmd.args.bindVertexBuffer.buffer != currentArrayBuffer) { + currentArrayBuffer = cmd.args.bindVertexBuffer.buffer; + // we do not support more than one vertex buffer + f->glBindBuffer(GL_ARRAY_BUFFER, currentArrayBuffer); + } const QRhiVertexInputBinding *inputBinding = psD->m_vertexInputLayout.bindingAt(bindingIdx); const int stride = int(inputBinding->stride()); @@ -2031,7 +2051,11 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb) quint32 ofs = it->offset() + cmd.args.bindVertexBuffer.offset; f->glVertexAttribPointer(GLuint(locationIdx), size, type, normalize, stride, reinterpret_cast(quintptr(ofs))); - f->glEnableVertexAttribArray(GLuint(locationIdx)); + if (locationIdx >= TRACKED_ATTRIB_COUNT || !enabledAttribArrays[locationIdx]) { + if (locationIdx < TRACKED_ATTRIB_COUNT) + enabledAttribArrays[locationIdx] = true; + f->glEnableVertexAttribArray(GLuint(locationIdx)); + } if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance && caps.instancing) f->glVertexAttribDivisor(GLuint(locationIdx), GLuint(inputBinding->instanceStepRate())); } @@ -2102,7 +2126,7 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb) } break; case QGles2CommandBuffer::Command::BindGraphicsPipeline: - executeBindGraphicsPipeline(cmd.args.bindGraphicsPipeline.ps); + executeBindGraphicsPipeline(cbD, QRHI_RES(QGles2GraphicsPipeline, cmd.args.bindGraphicsPipeline.ps)); break; case QGles2CommandBuffer::Command::BindShaderResources: bindShaderResources(cmd.args.bindShaderResources.maybeGraphicsPs, @@ -2148,6 +2172,7 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb) if (cmd.args.clear.mask & GL_STENCIL_BUFFER_BIT) f->glClearStencil(GLint(cmd.args.clear.s)); f->glClear(cmd.args.clear.mask); + cbD->graphicsPassState.reset(); // altered depth/color write, invalidate in order to avoid confusing the state tracking break; case QGles2CommandBuffer::Command::BufferSubData: f->glBindBuffer(cmd.args.bufferSubData.target, cmd.args.bufferSubData.buffer); @@ -2328,83 +2353,179 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb) } } -void QRhiGles2::executeBindGraphicsPipeline(QRhiGraphicsPipeline *ps) +void QRhiGles2::executeBindGraphicsPipeline(QGles2CommandBuffer *cbD, QGles2GraphicsPipeline *psD) { - QGles2GraphicsPipeline *psD = QRHI_RES(QGles2GraphicsPipeline, ps); + QGles2CommandBuffer::GraphicsPassState &state(cbD->graphicsPassState); + const bool forceUpdate = !state.valid; + state.valid = true; + + const bool scissor = psD->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor); + if (forceUpdate || scissor != state.scissor) { + state.scissor = scissor; + if (scissor) + f->glEnable(GL_SCISSOR_TEST); + else + f->glDisable(GL_SCISSOR_TEST); + } - // No state tracking logic as of now. Could introduce something to reduce - // the number of gl* calls (when using and changing between multiple - // pipelines), but then begin/endExternal() should invalidate the cached - // state as appropriate. + const bool cullFace = psD->m_cullMode != QRhiGraphicsPipeline::None; + const GLenum cullMode = cullFace ? toGlCullMode(psD->m_cullMode) : GL_NONE; + if (forceUpdate || cullFace != state.cullFace || cullMode != state.cullMode) { + state.cullFace = cullFace; + state.cullMode = cullMode; + if (cullFace) { + f->glEnable(GL_CULL_FACE); + f->glCullFace(cullMode); + } else { + f->glDisable(GL_CULL_FACE); + } + } - if (psD->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor)) - f->glEnable(GL_SCISSOR_TEST); - else - f->glDisable(GL_SCISSOR_TEST); - if (psD->m_cullMode == QRhiGraphicsPipeline::None) { - f->glDisable(GL_CULL_FACE); - } else { - f->glEnable(GL_CULL_FACE); - f->glCullFace(toGlCullMode(psD->m_cullMode)); + const GLenum frontFace = toGlFrontFace(psD->m_frontFace); + if (forceUpdate || frontFace != state.frontFace) { + state.frontFace = frontFace; + f->glFrontFace(frontFace); } - f->glFrontFace(toGlFrontFace(psD->m_frontFace)); + if (!psD->m_targetBlends.isEmpty()) { - const QRhiGraphicsPipeline::TargetBlend &blend(psD->m_targetBlends.first()); // no MRT - GLboolean wr = blend.colorWrite.testFlag(QRhiGraphicsPipeline::R); - GLboolean wg = blend.colorWrite.testFlag(QRhiGraphicsPipeline::G); - GLboolean wb = blend.colorWrite.testFlag(QRhiGraphicsPipeline::B); - GLboolean wa = blend.colorWrite.testFlag(QRhiGraphicsPipeline::A); - f->glColorMask(wr, wg, wb, wa); - if (blend.enable) { - f->glEnable(GL_BLEND); - f->glBlendFuncSeparate(toGlBlendFactor(blend.srcColor), - toGlBlendFactor(blend.dstColor), - toGlBlendFactor(blend.srcAlpha), - toGlBlendFactor(blend.dstAlpha)); - f->glBlendEquationSeparate(toGlBlendOp(blend.opColor), toGlBlendOp(blend.opAlpha)); - } else { - f->glDisable(GL_BLEND); + // We do not have MRT support here, meaning all targets use the blend + // params from the first one. This is technically incorrect, even if + // nothing in Qt relies on it. However, considering that + // glBlendFuncSeparatei is only available in GL 4.0+ and GLES 3.2+, we + // may just live with this for now because no point in bothering if it + // won't be usable on many GLES (3.1 or 3.0) systems. + const QRhiGraphicsPipeline::TargetBlend &targetBlend(psD->m_targetBlends.first()); + + const QGles2CommandBuffer::GraphicsPassState::ColorMask colorMask = { + targetBlend.colorWrite.testFlag(QRhiGraphicsPipeline::R), + targetBlend.colorWrite.testFlag(QRhiGraphicsPipeline::G), + targetBlend.colorWrite.testFlag(QRhiGraphicsPipeline::B), + targetBlend.colorWrite.testFlag(QRhiGraphicsPipeline::A) + }; + if (forceUpdate || colorMask != state.colorMask) { + state.colorMask = colorMask; + f->glColorMask(colorMask.r, colorMask.g, colorMask.b, colorMask.a); + } + + const bool blendEnabled = targetBlend.enable; + const QGles2CommandBuffer::GraphicsPassState::Blend blend = { + toGlBlendFactor(targetBlend.srcColor), + toGlBlendFactor(targetBlend.dstColor), + toGlBlendFactor(targetBlend.srcAlpha), + toGlBlendFactor(targetBlend.dstAlpha), + toGlBlendOp(targetBlend.opColor), + toGlBlendOp(targetBlend.opAlpha) + }; + if (forceUpdate || blendEnabled != state.blendEnabled || (blendEnabled && blend != state.blend)) { + state.blendEnabled = blendEnabled; + if (blendEnabled) { + state.blend = blend; + f->glEnable(GL_BLEND); + f->glBlendFuncSeparate(blend.srcColor, blend.dstColor, blend.srcAlpha, blend.dstAlpha); + f->glBlendEquationSeparate(blend.opColor, blend.opAlpha); + } else { + f->glDisable(GL_BLEND); + } } } else { - f->glDisable(GL_BLEND); - f->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + const QGles2CommandBuffer::GraphicsPassState::ColorMask colorMask = { true, true, true, true }; + if (forceUpdate || colorMask != state.colorMask) { + state.colorMask = colorMask; + f->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } + const bool blendEnabled = false; + if (forceUpdate || blendEnabled != state.blendEnabled) { + state.blendEnabled = blendEnabled; + f->glDisable(GL_BLEND); + } } - if (psD->m_depthTest) - f->glEnable(GL_DEPTH_TEST); - else - f->glDisable(GL_DEPTH_TEST); - if (psD->m_depthWrite) - f->glDepthMask(GL_TRUE); - else - f->glDepthMask(GL_FALSE); - f->glDepthFunc(toGlCompareOp(psD->m_depthOp)); - if (psD->m_stencilTest) { - f->glEnable(GL_STENCIL_TEST); - f->glStencilFuncSeparate(GL_FRONT, toGlCompareOp(psD->m_stencilFront.compareOp), 0, psD->m_stencilReadMask); - f->glStencilOpSeparate(GL_FRONT, - toGlStencilOp(psD->m_stencilFront.failOp), - toGlStencilOp(psD->m_stencilFront.depthFailOp), - toGlStencilOp(psD->m_stencilFront.passOp)); - f->glStencilMaskSeparate(GL_FRONT, psD->m_stencilWriteMask); - f->glStencilFuncSeparate(GL_BACK, toGlCompareOp(psD->m_stencilBack.compareOp), 0, psD->m_stencilReadMask); - f->glStencilOpSeparate(GL_BACK, - toGlStencilOp(psD->m_stencilBack.failOp), - toGlStencilOp(psD->m_stencilBack.depthFailOp), - toGlStencilOp(psD->m_stencilBack.passOp)); - f->glStencilMaskSeparate(GL_BACK, psD->m_stencilWriteMask); - } else { - f->glDisable(GL_STENCIL_TEST); + + const bool depthTest = psD->m_depthTest; + if (forceUpdate || depthTest != state.depthTest) { + state.depthTest = depthTest; + if (depthTest) + f->glEnable(GL_DEPTH_TEST); + else + f->glDisable(GL_DEPTH_TEST); } - if (psD->m_depthBias != 0 || !qFuzzyIsNull(psD->m_slopeScaledDepthBias)) { - f->glPolygonOffset(psD->m_slopeScaledDepthBias, psD->m_depthBias); - f->glEnable(GL_POLYGON_OFFSET_FILL); - } else { - f->glDisable(GL_POLYGON_OFFSET_FILL); + const bool depthWrite = psD->m_depthWrite; + if (forceUpdate || depthWrite != state.depthWrite) { + state.depthWrite = depthWrite; + f->glDepthMask(depthWrite); + } + + const GLenum depthFunc = toGlCompareOp(psD->m_depthOp); + if (forceUpdate || depthFunc != state.depthFunc) { + state.depthFunc = depthFunc; + f->glDepthFunc(depthFunc); } - if (psD->m_topology == QRhiGraphicsPipeline::Lines || psD->m_topology == QRhiGraphicsPipeline::LineStrip) - f->glLineWidth(psD->m_lineWidth); + const bool stencilTest = psD->m_stencilTest; + const GLuint stencilReadMask = psD->m_stencilReadMask; + const GLuint stencilWriteMask = psD->m_stencilWriteMask; + const QGles2CommandBuffer::GraphicsPassState::StencilFace stencilFront = { + toGlCompareOp(psD->m_stencilFront.compareOp), + toGlStencilOp(psD->m_stencilFront.failOp), + toGlStencilOp(psD->m_stencilFront.depthFailOp), + toGlStencilOp(psD->m_stencilFront.passOp) + }; + const QGles2CommandBuffer::GraphicsPassState::StencilFace stencilBack = { + toGlCompareOp(psD->m_stencilBack.compareOp), + toGlStencilOp(psD->m_stencilBack.failOp), + toGlStencilOp(psD->m_stencilBack.depthFailOp), + toGlStencilOp(psD->m_stencilBack.passOp) + }; + if (forceUpdate || stencilTest != state.stencilTest + || (stencilTest + && (stencilReadMask != state.stencilReadMask || stencilWriteMask != state.stencilWriteMask + || stencilFront != state.stencil[0] || stencilBack != state.stencil[1]))) + { + state.stencilTest = stencilTest; + if (stencilTest) { + state.stencilReadMask = stencilReadMask; + state.stencilWriteMask = stencilWriteMask; + state.stencil[0] = stencilFront; + state.stencil[1] = stencilBack; + + f->glEnable(GL_STENCIL_TEST); + + f->glStencilFuncSeparate(GL_FRONT, stencilFront.func, state.dynamic.stencilRef, stencilReadMask); + f->glStencilOpSeparate(GL_FRONT, stencilFront.failOp, stencilFront.zfailOp, stencilFront.zpassOp); + f->glStencilMaskSeparate(GL_FRONT, stencilWriteMask); + + f->glStencilFuncSeparate(GL_BACK, stencilBack.func, state.dynamic.stencilRef, stencilReadMask); + f->glStencilOpSeparate(GL_BACK, stencilBack.failOp, stencilBack.zfailOp, stencilBack.zpassOp); + f->glStencilMaskSeparate(GL_BACK, stencilWriteMask); + } else { + f->glDisable(GL_STENCIL_TEST); + } + } + + const bool polyOffsetFill = psD->m_depthBias != 0 || !qFuzzyIsNull(psD->m_slopeScaledDepthBias); + const float polyOffsetFactor = psD->m_slopeScaledDepthBias; + const float polyOffsetUnits = psD->m_depthBias; + if (forceUpdate || state.polyOffsetFill != polyOffsetFill + || polyOffsetFactor != state.polyOffsetFactor || polyOffsetUnits != state.polyOffsetUnits) + { + state.polyOffsetFill = polyOffsetFill; + state.polyOffsetFactor = polyOffsetFactor; + state.polyOffsetUnits = polyOffsetUnits; + if (polyOffsetFill) { + f->glPolygonOffset(polyOffsetFactor, polyOffsetUnits); + f->glEnable(GL_POLYGON_OFFSET_FILL); + } else { + f->glDisable(GL_POLYGON_OFFSET_FILL); + } + } + + if (psD->m_topology == QRhiGraphicsPipeline::Lines || psD->m_topology == QRhiGraphicsPipeline::LineStrip) { + const float lineWidth = psD->m_lineWidth; + if (forceUpdate || lineWidth != state.lineWidth) { + state.lineWidth = lineWidth; + f->glLineWidth(lineWidth); + } + } f->glUseProgram(psD->program); } @@ -2827,8 +2948,6 @@ void QRhiGles2::beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch cbD->recordingPass = QGles2CommandBuffer::ComputePass; cbD->resetCachedState(); - - cbD->computePassState.reset(); } void QRhiGles2::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h index 8b7d01532a..ac7b384cb6 100644 --- a/src/gui/rhi/qrhigles2_p_p.h +++ b/src/gui/rhi/qrhigles2_p_p.h @@ -522,6 +522,45 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer QRhiShaderResourceBindings *currentComputeSrb; uint currentSrbGeneration; + struct GraphicsPassState { + bool valid = false; + bool scissor; + bool cullFace; + GLenum cullMode; + GLenum frontFace; + bool blendEnabled; + struct ColorMask { bool r, g, b, a; } colorMask; + struct Blend { + GLenum srcColor; + GLenum dstColor; + GLenum srcAlpha; + GLenum dstAlpha; + GLenum opColor; + GLenum opAlpha; + } blend; + bool depthTest; + bool depthWrite; + GLenum depthFunc; + bool stencilTest; + GLuint stencilReadMask; + GLuint stencilWriteMask; + struct StencilFace { + GLenum func; + GLenum failOp; + GLenum zfailOp; + GLenum zpassOp; + } stencil[2]; // front, back + bool polyOffsetFill; + float polyOffsetFactor; + float polyOffsetUnits; + float lineWidth; + void reset() { valid = false; } + struct { + // not part of QRhiGraphicsPipeline but used by setGraphicsPipeline() + GLint stencilRef = 0; + } dynamic; + } graphicsPassState; + struct ComputePassState { enum Access { Read = 0x01, @@ -566,11 +605,57 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer currentGraphicsSrb = nullptr; currentComputeSrb = nullptr; currentSrbGeneration = 0; + graphicsPassState.reset(); + computePassState.reset(); } }; Q_DECLARE_TYPEINFO(QGles2CommandBuffer::Command, Q_MOVABLE_TYPE); +inline bool operator==(const QGles2CommandBuffer::GraphicsPassState::StencilFace &a, + const QGles2CommandBuffer::GraphicsPassState::StencilFace &b) +{ + return a.func == b.func + && a.failOp == b.failOp + && a.zfailOp == b.zfailOp + && a.zpassOp == b.zpassOp; +} + +inline bool operator!=(const QGles2CommandBuffer::GraphicsPassState::StencilFace &a, + const QGles2CommandBuffer::GraphicsPassState::StencilFace &b) +{ + return !(a == b); +} + +inline bool operator==(const QGles2CommandBuffer::GraphicsPassState::ColorMask &a, + const QGles2CommandBuffer::GraphicsPassState::ColorMask &b) +{ + return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a; +} + +inline bool operator!=(const QGles2CommandBuffer::GraphicsPassState::ColorMask &a, + const QGles2CommandBuffer::GraphicsPassState::ColorMask &b) +{ + return !(a == b); +} + +inline bool operator==(const QGles2CommandBuffer::GraphicsPassState::Blend &a, + const QGles2CommandBuffer::GraphicsPassState::Blend &b) +{ + return a.srcColor == b.srcColor + && a.dstColor == b.dstColor + && a.srcAlpha == b.srcAlpha + && a.dstAlpha == b.dstAlpha + && a.opColor == b.opColor + && a.opAlpha == b.opAlpha; +} + +inline bool operator!=(const QGles2CommandBuffer::GraphicsPassState::Blend &a, + const QGles2CommandBuffer::GraphicsPassState::Blend &b) +{ + return !(a == b); +} + struct QGles2SwapChain : public QRhiSwapChain { QGles2SwapChain(QRhiImplementation *rhi); @@ -709,7 +794,7 @@ public: QRhiPassResourceTracker::TextureAccess access, QRhiPassResourceTracker::TextureStage stage); void executeCommandBuffer(QRhiCommandBuffer *cb); - void executeBindGraphicsPipeline(QRhiGraphicsPipeline *ps); + void executeBindGraphicsPipeline(QGles2CommandBuffer *cbD, QGles2GraphicsPipeline *psD); void bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiComputePipeline *maybeComputePs, QRhiShaderResourceBindings *srb, const uint *dynOfsPairs, int dynOfsCount); -- cgit v1.2.3 From aa5855847c158524ceaa99f2e99fb2eba5b118af Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 18 Mar 2020 12:19:37 +0100 Subject: Add SSE2 optimized solid source composition Very similar to source-over, but have traditionally been inlined. Change-Id: I211f0b1c91c1a00c4769fbbfe2e3d0c7b22d7048 Reviewed-by: Eirik Aavitsland --- src/gui/painting/qdrawhelper.cpp | 6 ++++++ src/gui/painting/qdrawhelper_sse2.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) (limited to 'src/gui') diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 4b0cc2547c..39de1baa17 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -4521,6 +4521,10 @@ static void blend_color_argb(int count, const QSpan *spans, void *userData) uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x; if (spans->coverage == 255) { qt_memfill(target, color, spans->len); +#ifdef __SSE2__ + } else if (spans->len > 16) { + op.funcSolid(target, spans->len, color, spans->coverage); +#endif } else { uint c = BYTE_MUL(color, spans->coverage); int ialpha = 255 - spans->coverage; @@ -6764,10 +6768,12 @@ static void qInitDrawhelperFunctions() extern void QT_FASTCALL comp_func_SourceOver_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); extern void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha); extern void QT_FASTCALL comp_func_Source_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); + extern void QT_FASTCALL comp_func_solid_Source_sse2(uint *destPixels, int length, uint color, uint const_alpha); extern void QT_FASTCALL comp_func_Plus_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_sse2; qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_sse2; qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_sse2; + qt_functionForModeSolid_C[QPainter::CompositionMode_Source] = comp_func_solid_Source_sse2; qt_functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_sse2; #ifdef QT_COMPILER_SUPPORTS_SSSE3 diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp index c82f41ec88..77b5ab42c5 100644 --- a/src/gui/painting/qdrawhelper_sse2.cpp +++ b/src/gui/painting/qdrawhelper_sse2.cpp @@ -319,6 +319,35 @@ void qt_memfill32_sse2(quint32 *dest, quint32 value, qsizetype count) } #endif // !__AVX2__ +void QT_FASTCALL comp_func_solid_Source_sse2(uint *destPixels, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) { + qt_memfill32(destPixels, color, length); + } else { + const quint32 ialpha = 255 - const_alpha; + color = BYTE_MUL(color, const_alpha); + int x = 0; + + quint32 *dst = (quint32 *) destPixels; + const __m128i colorVector = _mm_set1_epi32(color); + const __m128i colorMask = _mm_set1_epi32(0x00ff00ff); + const __m128i half = _mm_set1_epi16(0x80); + const __m128i iAlphaVector = _mm_set1_epi16(ialpha); + + ALIGNMENT_PROLOGUE_16BYTES(dst, x, length) + destPixels[x] = color + BYTE_MUL(destPixels[x], ialpha); + + for (; x < length-3; x += 4) { + __m128i dstVector = _mm_load_si128((__m128i *)&dst[x]); + BYTE_MUL_SSE2(dstVector, dstVector, iAlphaVector, colorMask, half); + dstVector = _mm_add_epi8(colorVector, dstVector); + _mm_store_si128((__m128i *)&dst[x], dstVector); + } + SIMD_EPILOGUE(x, length, 3) + destPixels[x] = color + BYTE_MUL(destPixels[x], ialpha); + } +} + void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha) { if ((const_alpha & qAlpha(color)) == 255) { -- cgit v1.2.3 From bd75c87e0e76b328827a2aad1077f89e50e36d9d Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Wed, 18 Mar 2020 19:56:40 +0100 Subject: Doc: replace deprecated references to QGLWidget Remove references to the deprecated QGLWidget and replace it with QOpenGLWidget. Change-Id: Ia31df42ab61c25e9ce46f4491267d2c64910f55c Reviewed-by: Paul Wicking --- src/gui/painting/qpaintengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/gui') diff --git a/src/gui/painting/qpaintengine.cpp b/src/gui/painting/qpaintengine.cpp index 315bf0daf2..6b34911c15 100644 --- a/src/gui/painting/qpaintengine.cpp +++ b/src/gui/painting/qpaintengine.cpp @@ -158,7 +158,7 @@ QFont QTextItem::font() const X11 and \macos, it is the backend for painting on QImage and it is used as a fallback for paint engines that do not support a certain capability. In addition we provide QPaintEngine implementations for - OpenGL (accessible through QGLWidget) and printing (which allows using + OpenGL (accessible through QOpenGLWidget) and printing (which allows using QPainter to draw on a QPrinter object). If one wants to use QPainter to draw to a different backend, -- cgit v1.2.3 From cb509f3aeeea2a905b696f3914fa6d03c9106f71 Mon Sep 17 00:00:00 2001 From: Joni Poikelin Date: Mon, 17 Feb 2020 14:40:26 +0200 Subject: Doc: fix copy paste errors in border-*-style documentation Change-Id: I442513ec87e25610898c2102170a5f2bfec5ee77 Reviewed-by: Shawn Rutledge --- src/gui/doc/src/richtext.qdoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/gui') diff --git a/src/gui/doc/src/richtext.qdoc b/src/gui/doc/src/richtext.qdoc index 31a2ebf05b..1ef34455ab 100644 --- a/src/gui/doc/src/richtext.qdoc +++ b/src/gui/doc/src/richtext.qdoc @@ -1197,16 +1197,16 @@ \li none | dotted | dashed | dot-dash | dot-dot-dash | solid | double | groove | ridge | inset | outset \li Border style for text tables and table cells. \row \li \c border-top-style - \li + \li \li Top border style for table cells. \row \li \c border-bottom-style - \li + \li \li Bottom border style for table cells. \row \li \c border-left-style - \li + \li \li Left border style for table cells. \row \li \c border-right-style - \li + \li \li Right border style for table cells. \row \li \c border-width \li px -- cgit v1.2.3 From b4b8ffb2339d5bd889e3d60c7e264e10a561ab43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Micha=C3=ABl=20Celerier?= Date: Thu, 19 Mar 2020 17:30:47 +0100 Subject: rhi: gles2: fix uniform gathering after struct-type member in UBOs Given: struct Light { vec4 foo; }; layout(std140, binding = 2) uniform material { Light light; int lightCount; }; the previous code would keep "light" appended for the prefix and look for `light.lightCount`. Change-Id: Ia8deacd0cb4833f45151e922fa7b5970169332eb Reviewed-by: Laszlo Agocs --- src/gui/rhi/qrhigles2.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/gui') diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 52c5c70d3f..395ae4b93f 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -3256,11 +3256,12 @@ void QRhiGles2::gatherUniforms(GLuint program, QByteArray prefix = ub.structName.toUtf8() + '.'; for (const QShaderDescription::BlockVariable &blockMember : ub.members) { if (blockMember.type == QShaderDescription::Struct) { - prefix += blockMember.name.toUtf8(); + QByteArray structPrefix = prefix + blockMember.name.toUtf8(); + const int baseOffset = blockMember.offset; if (blockMember.arrayDims.isEmpty()) { for (const QShaderDescription::BlockVariable &structMember : blockMember.structMembers) - registerUniformIfActive(structMember, prefix, ub.binding, baseOffset, program, dst); + registerUniformIfActive(structMember, structPrefix, ub.binding, baseOffset, program, dst); } else { if (blockMember.arrayDims.count() > 1) { qWarning("Array of struct '%s' has more than one dimension. Only the first dimension is used.", @@ -3270,7 +3271,7 @@ void QRhiGles2::gatherUniforms(GLuint program, const int elemSize = blockMember.size / dim; int elemOffset = baseOffset; for (int di = 0; di < dim; ++di) { - const QByteArray arrayPrefix = prefix + '[' + QByteArray::number(di) + ']' + '.'; + const QByteArray arrayPrefix = structPrefix + '[' + QByteArray::number(di) + ']' + '.'; for (const QShaderDescription::BlockVariable &structMember : blockMember.structMembers) registerUniformIfActive(structMember, arrayPrefix, ub.binding, elemOffset, program, dst); elemOffset += elemSize; -- cgit v1.2.3 From 5e1e4b9d52987c7c12a935e0ed5ef89f1ca8244c Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 18 Mar 2020 12:22:11 +0100 Subject: Extend tiled optimization in 64-bit painting to 64-bit sources Change-Id: I74b88781d631ee68822cd08f9cb0aca03f7b688e Reviewed-by: Eirik Aavitsland --- src/gui/painting/qdrawhelper.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'src/gui') diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 39de1baa17..f153557077 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -5139,7 +5139,8 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD yoff += image_height; bool isBpp32 = qPixelLayouts[data->rasterBuffer->format].bpp == QPixelLayout::BPP32; - if (op.destFetch64 == destFetch64Undefined && image_width <= BufferSize && isBpp32) { + bool isBpp64 = qPixelLayouts[data->rasterBuffer->format].bpp == QPixelLayout::BPP64; + if (op.destFetch64 == destFetch64Undefined && image_width <= BufferSize && (isBpp32 || isBpp64)) { // If destination isn't blended into the result, we can do the tiling directly on destination pixels. while (count--) { int x = spans->x; @@ -5173,9 +5174,14 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD if (sx >= image_width) sx = 0; } - uint *dest = (uint*)data->rasterBuffer->scanLine(y) + x - image_width; - for (int i = image_width; i < length; ++i) { - dest[i] = dest[i - image_width]; + if (isBpp32) { + uint *dest = reinterpret_cast(data->rasterBuffer->scanLine(y)) + x - image_width; + for (int i = image_width; i < length; ++i) + dest[i] = dest[i - image_width]; + } else { + quint64 *dest = reinterpret_cast(data->rasterBuffer->scanLine(y)) + x - image_width; + for (int i = image_width; i < length; ++i) + dest[i] = dest[i - image_width]; } ++spans; } -- cgit v1.2.3 From b15ed929f3f481914bf96203e691a552f6d9fe00 Mon Sep 17 00:00:00 2001 From: Giulio Camuffo Date: Fri, 20 Mar 2020 14:05:34 +0100 Subject: Fix memory leak When creating a new QColorSpacePrivate it must be reffed otherwise in the destructor the deref() will bring the count to -1 which is true and will not delete the d_ptr. Change-Id: Id569bae22134b56bf6ad37158d7079b495599fd7 Reviewed-by: Allan Sandfeld Jensen (cherry picked from commit 20eabb72de94ddcef3c36b5cad0ce88944d42f8c) --- src/gui/painting/qcolorspace.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/gui') diff --git a/src/gui/painting/qcolorspace.cpp b/src/gui/painting/qcolorspace.cpp index 7e7bbec870..930e5aec87 100644 --- a/src/gui/painting/qcolorspace.cpp +++ b/src/gui/painting/qcolorspace.cpp @@ -553,6 +553,7 @@ void QColorSpace::setTransferFunction(QColorSpace::TransferFunction transferFunc return; if (!d_ptr) { d_ptr = new QColorSpacePrivate(Primaries::Custom, transferFunction, gamma); + d_ptr->ref.ref(); return; } if (d_ptr->transferFunction == transferFunction && d_ptr->gamma == gamma) @@ -593,6 +594,7 @@ void QColorSpace::setPrimaries(QColorSpace::Primaries primariesId) return; if (!d_ptr) { d_ptr = new QColorSpacePrivate(primariesId, TransferFunction::Custom, 0.0f); + d_ptr->ref.ref(); return; } if (d_ptr->primaries == primariesId) @@ -618,6 +620,7 @@ void QColorSpace::setPrimaries(const QPointF &whitePoint, const QPointF &redPoin return; if (!d_ptr) { d_ptr = new QColorSpacePrivate(primaries, TransferFunction::Custom, 0.0f); + d_ptr->ref.ref(); return; } QColorMatrix toXyz = primaries.toXyzMatrix(); -- cgit v1.2.3 From b1e3f33a28aad1d9386ff2ef569db90341a8d68a Mon Sep 17 00:00:00 2001 From: Michal Klocek Date: Thu, 12 Mar 2020 17:07:08 +0100 Subject: Call post routines from ~QGuiApplication MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently depending if user uses QApplication or QGuiApplication we end up in different behavior when running post routines. For example QApplication destructor calls post routines before stopping event dispatcher, In case of QGuiApplication post routines are called from QCoreApplication destructor, so no more event dispatcher. This behavior is not consistent and creates troubles when releasing resources of web engine. Attached test will hang on windows with QGuiApplication, however works fine with QApplication. Task-number: QTBUG-79864 Change-Id: Ice05e66a467feaf3ad6addfbc14973649da8065e Reviewed-by: Tor Arne Vestbø --- src/gui/kernel/qguiapplication.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/gui') diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 469563c415..b9e8db8789 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -134,6 +134,7 @@ QT_BEGIN_NAMESPACE return __VA_ARGS__; \ } +Q_CORE_EXPORT void qt_call_post_routines(); Q_GUI_EXPORT bool qt_is_gui_used = true; Qt::MouseButtons QGuiApplicationPrivate::mouse_buttons = Qt::NoButton; @@ -678,6 +679,8 @@ QGuiApplication::~QGuiApplication() { Q_D(QGuiApplication); + qt_call_post_routines(); + d->eventDispatcher->closingDown(); d->eventDispatcher = nullptr; -- cgit v1.2.3 From a320b57f1d8532fc5ab00aed7a78c7f2f828da53 Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Tue, 24 Mar 2020 14:23:02 +0100 Subject: Doc: Don't mention deprecated functions in QTabletEvent overview Change-Id: I5d41d6061403f2923d673376be7cf1250d0f0e82 Reviewed-by: Paul Wicking Reviewed-by: Shawn Rutledge --- src/gui/kernel/qevent.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/gui') diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 17aa550606..bda0949764 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -2225,14 +2225,14 @@ QVariant QInputMethodQueryEvent::value(Qt::InputMethodQuery query) const (pressing the stylus tip against the tablet surface is equivalent to a left mouse button). But tablet events also pass through some extra information that the tablet device driver provides; for example, you might want to do - subpixel rendering with higher resolution coordinates (\l hiResGlobalX() - and \l hiResGlobalY()), adjust color brightness based on the \l pressure() - of the tool against the tablet surface, use different brushes depending on - the type of tool in use (\l device()), modulate the brush shape in some way - according to the X-axis and Y-axis tilt of the tool with respect to the - tablet surface (\l xTilt() and \l yTilt()), and use a virtual eraser - instead of a brush if the user switches to the other end of a double-ended - stylus (\l pointerType()). + subpixel rendering with higher resolution coordinates (\l globalPosF()), + adjust color brightness based on the \l pressure() of the tool against the + tablet surface, use different brushes depending on the type of tool in use + (\l deviceType()), modulate the brush shape in some way according to the + X-axis and Y-axis tilt of the tool with respect to the tablet surface + (\l xTilt() and \l yTilt()), and use a virtual eraser instead of a brush if + the user switches to the other end of a double-ended stylus + (\l pointerType()). Every event contains an accept flag that indicates whether the receiver wants the event. You should call QTabletEvent::accept() if you handle the -- cgit v1.2.3 From c81b172781a35590a4f0345aa35e947d8e780694 Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Tue, 17 Mar 2020 23:51:45 +0100 Subject: Doc: Mark gamma-related functions deprecated in QImageReader/Writer Change-Id: I0a9fbcca7a10a6555f5879cc4955f046eaa56602 Reviewed-by: Lars Knoll Reviewed-by: Paul Wicking --- src/gui/image/qimagereader.cpp | 4 +++- src/gui/image/qimagewriter.cpp | 19 +++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) (limited to 'src/gui') diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp index 3eb1e01863..5cb7e1328e 100644 --- a/src/gui/image/qimagereader.cpp +++ b/src/gui/image/qimagereader.cpp @@ -101,7 +101,7 @@ This can be disabled by setting the environment variable \c QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING. - \sa QImageWriter, QImageIOHandler, QImageIOPlugin, QMimeDatabase + \sa QImageWriter, QImageIOHandler, QImageIOPlugin, QMimeDatabase, QColorSpace \sa QImage::devicePixelRatio(), QPixmap::devicePixelRatio(), QIcon, QPainter::drawPixmap(), QPainter::drawImage(), Qt::AA_UseHighDpiPixmaps */ @@ -1152,6 +1152,7 @@ bool QImageReader::autoTransform() const #if QT_DEPRECATED_SINCE(5, 15) /*! \since 5.6 + \obsolete Use QColorSpace conversion on the QImage instead. This is an image format specific function that forces images with gamma information to be gamma corrected to \a gamma. For image formats @@ -1169,6 +1170,7 @@ void QImageReader::setGamma(float gamma) /*! \since 5.6 + \obsolete Use QImage::colorSpace() and QColorSpace::gamma() instead. Returns the gamma level of the decoded image. If setGamma() has been called and gamma correction is supported it will return the gamma set. diff --git a/src/gui/image/qimagewriter.cpp b/src/gui/image/qimagewriter.cpp index 6e74b23f76..33f5e491c7 100644 --- a/src/gui/image/qimagewriter.cpp +++ b/src/gui/image/qimagewriter.cpp @@ -47,19 +47,18 @@ \ingroup painting \ingroup io - QImageWriter supports setting format specific options, such as the - gamma level, compression level and quality, prior to storing the + QImageWriter supports setting format specific options, such as + compression level and quality, prior to storing the image. If you do not need such options, you can use QImage::save() or QPixmap::save() instead. To store an image, you start by constructing a QImageWriter object. Pass either a file name or a device pointer, and the image format to QImageWriter's constructor. You can then set - several options, such as the gamma level (by calling setGamma()) - and quality (by calling setQuality()). canWrite() returns \c true if - QImageWriter can write the image (i.e., the image format is - supported and the device is open for writing). Call write() to - write the image to the device. + several options, such as quality (by calling setQuality()). + canWrite() returns \c true if QImageWriter can write the image + (i.e., the image format is supported and the device is open for + writing). Call write() to write the image to the device. If any error occurs when writing the image, write() will return false. You can then call error() to find the type of error that @@ -81,7 +80,7 @@ \snippet qimagewriter/main.cpp 0 - \sa QImageReader, QImageIOHandler, QImageIOPlugin + \sa QImageReader, QImageIOHandler, QImageIOPlugin, QColorSpace */ /*! @@ -500,6 +499,8 @@ int QImageWriter::compression() const #if QT_DEPRECATED_SINCE(5, 15) /*! + \obsolete Use QColorSpace conversion on the QImage instead. + This is an image format specific function that sets the gamma level of the image to \a gamma. For image formats that do not support setting the gamma level, this value is ignored. @@ -515,6 +516,8 @@ void QImageWriter::setGamma(float gamma) } /*! + \obsolete Use QImage::colorSpace() and QColorSpace::gamma() instead. + Returns the gamma level of the image. \sa setGamma() -- cgit v1.2.3 From 533f7d7ca328e81804c8f52818f9d39172694f94 Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Fri, 27 Mar 2020 09:41:03 +0100 Subject: Raster painting: fix dashing for separate lines When drawing multiple distinct (unconnected) lines (e.g. from QPainter::drawLines() or a QPainterPath with alternating movetos/linetos), the dash pattern should not continue from one to the next, as it should when drawing a connected line (e.g. polyline). Both the cosmetic stroker and the full stroker does it right, but the fast rasterizing codepath got it wrong. Fixes: QTBUG-83048 Change-Id: I3d090f7121726755a0e53cb66b99a5563ac0e1c0 Reviewed-by: Allan Sandfeld Jensen --- src/gui/painting/qpaintengine_raster.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/gui') diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 10920c38fe..5b7f8511ba 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -1713,8 +1713,11 @@ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen) width / line.length(), s->lastPen.capStyle() == Qt::SquareCap); } else { - d->rasterizeLine_dashed(line, width, - &dashIndex, &dashOffset, &inDash); + // LinesHint means each line is distinct, so restart dashing + int dIndex = dashIndex; + qreal dOffset = dashOffset; + bool inD = inDash; + d->rasterizeLine_dashed(line, width, &dIndex, &dOffset, &inD); } } } -- cgit v1.2.3 From 68916fede41d1eca5d07eb6b1db518d41a007616 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 30 Mar 2020 12:07:29 +0200 Subject: Finish deprecating TouchPoint::rect, sceneRect and screenRect accessors All 6 getters and setters were deprecated by doc comment \obsolete in 3c159957f863cf8d367a9261e7016e52cd0348c1 (Qt 5.9). Now we will generate compiler warnings too. Change-Id: I94c6da607fa5758072af1287c9286b6c52179cfb Reviewed-by: Frederik Gladhorn --- src/gui/kernel/qevent.cpp | 30 +++++++----------------------- src/gui/kernel/qevent.h | 16 +++++++++++++--- 2 files changed, 20 insertions(+), 26 deletions(-) (limited to 'src/gui') diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index bda0949764..466e70db30 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -4653,19 +4653,12 @@ QPointF QTouchEvent::TouchPoint::lastNormalizedPos() const return d->lastNormalizedPos; } +#if QT_DEPRECATED_SINCE(5, 15) /*! - Returns the rect for this touch point, relative to the widget - or QGraphicsItem that received the event. The rect is centered - around the point returned by pos(). - - \note This function returns an empty rect if the device does not report touch point sizes. - - \obsolete This function is deprecated in 5.9 because it returns the outer bounds + \deprecated This function is deprecated since 5.9 because it returns the outer bounds of the touchpoint regardless of rotation, whereas a touchpoint is more correctly modeled as an ellipse at position pos() with ellipseDiameters() which are independent of rotation(). - - \sa scenePos(), ellipseDiameters() */ QRectF QTouchEvent::TouchPoint::rect() const { @@ -4675,16 +4668,10 @@ QRectF QTouchEvent::TouchPoint::rect() const } /*! - Returns the rect for this touch point in scene coordinates. - - \note This function returns an empty rect if the device does not report touch point sizes. - - \obsolete This function is deprecated in 5.9 because it returns the outer bounds + \deprecated This function is deprecated since 5.9 because it returns the outer bounds of the touchpoint regardless of rotation, whereas a touchpoint is more correctly modeled as an ellipse at position scenePos() with ellipseDiameters() which are independent of rotation(). - - \sa scenePos(), ellipseDiameters() */ QRectF QTouchEvent::TouchPoint::sceneRect() const { @@ -4694,16 +4681,10 @@ QRectF QTouchEvent::TouchPoint::sceneRect() const } /*! - Returns the rect for this touch point in screen coordinates. - - \note This function returns an empty rect if the device does not report touch point sizes. - - \obsolete This function is deprecated because it returns the outer bounds of the + \deprecated This function is deprecated since 5.9 because it returns the outer bounds of the touchpoint regardless of rotation, whereas a touchpoint is more correctly modeled as an ellipse at position screenPos() with ellipseDiameters() which are independent of rotation(). - - \sa screenPos(), ellipseDiameters() */ QRectF QTouchEvent::TouchPoint::screenRect() const { @@ -4711,6 +4692,7 @@ QRectF QTouchEvent::TouchPoint::screenRect() const ret.moveCenter(d->screenPos); return ret; } +#endif /*! Returns the pressure of this touch point. The return value is in @@ -4909,6 +4891,7 @@ void QTouchEvent::TouchPoint::setLastNormalizedPos(const QPointF &lastNormalized d->lastNormalizedPos = lastNormalizedPos; } +#if QT_DEPRECATED_SINCE(5, 15) // ### remove the following 3 setRect functions and their usages soon /*! \internal \obsolete @@ -4942,6 +4925,7 @@ void QTouchEvent::TouchPoint::setScreenRect(const QRectF &screenRect) d->screenPos = screenRect.center(); d->ellipseDiameters = screenRect.size(); } +#endif /*! \internal */ void QTouchEvent::TouchPoint::setPressure(qreal pressure) diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index cf596d8d45..4aba9ff729 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -933,10 +933,23 @@ public: QPointF startNormalizedPos() const; QPointF lastNormalizedPos() const; +#if QT_DEPRECATED_SINCE(5, 15) + // All these are actually deprecated since 5.9, in docs + QT_DEPRECATED_VERSION_X_5_15("Use pos() and ellipseDiameters()") QRectF rect() const; + QT_DEPRECATED_VERSION_X_5_15("Use scenePos() and ellipseDiameters()") QRectF sceneRect() const; + QT_DEPRECATED_VERSION_X_5_15("Use screenPos() and ellipseDiameters()") QRectF screenRect() const; + // internal + QT_DEPRECATED_VERSION_X_5_15("Use setPos() and setEllipseDiameters()") + void setRect(const QRectF &rect); // deprecated + QT_DEPRECATED_VERSION_X_5_15("Use setScenePos() and setEllipseDiameters()") + void setSceneRect(const QRectF &sceneRect); // deprecated + QT_DEPRECATED_VERSION_X_5_15("Use setScreenPos() and setEllipseDiameters()") + void setScreenRect(const QRectF &screenRect); // deprecated +#endif qreal pressure() const; qreal rotation() const; QSizeF ellipseDiameters() const; @@ -961,9 +974,6 @@ public: void setLastScenePos(const QPointF &lastScenePos); void setLastScreenPos(const QPointF &lastScreenPos); void setLastNormalizedPos(const QPointF &lastNormalizedPos); - void setRect(const QRectF &rect); // deprecated - void setSceneRect(const QRectF &sceneRect); // deprecated - void setScreenRect(const QRectF &screenRect); // deprecated void setPressure(qreal pressure); void setRotation(qreal angle); void setEllipseDiameters(const QSizeF &dia); -- cgit v1.2.3 From 8f88a3962a7b1716d2c0482b818d2504776ece05 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 30 Mar 2020 17:20:35 +0200 Subject: Fix 1 pixel wide images Images are rounded up to 4 bytes per line minimum, so one pixel wide images might not shrink when resizing. Fixes: QTBUG-83179 Change-Id: If72c94409e4c899c5ad05b2867f5f53a94d0580f Reviewed-by: Christian Kamm --- src/gui/image/qimage_conversions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/gui') diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index 6ddd08d08d..853bbe4f8e 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -426,8 +426,8 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im data->nbytes = params.totalSize; } data->bytes_per_line = params.bytesPerLine; - data->depth = destDepth; } + data->depth = destDepth; data->format = dst_format; return true; } -- cgit v1.2.3 From 5c1bc5c8a41e9d4b40161eae1413bcb69325dd8f Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Fri, 27 Mar 2020 14:10:43 +0100 Subject: QLineEdit: clarify the impact of using validators Values that are validated as Intermediate are possible to enter, but returnPressed and editingFinished signals are not emitted. Fixes: QTBUG-82915 Change-Id: I3e194cd6ee93b3402090117b67044cf3663a232e Reviewed-by: Paul Wicking Reviewed-by: Edward Welbourne --- src/gui/util/qvalidator.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/gui') diff --git a/src/gui/util/qvalidator.cpp b/src/gui/util/qvalidator.cpp index 54cbb28ffa..6e87faf534 100644 --- a/src/gui/util/qvalidator.cpp +++ b/src/gui/util/qvalidator.cpp @@ -370,8 +370,9 @@ QIntValidator::~QIntValidator() \fn QValidator::State QIntValidator::validate(QString &input, int &pos) const Returns \l Acceptable if the \a input is an integer within the - valid range, \l Intermediate if the \a input is a prefix of an integer in the - valid range, and \l Invalid otherwise. + valid range. If \a input has at most as many digits as the top of the range, + or is a prefix of an integer in the valid range, returns \l Intermediate. + Otherwise, returns \l Invalid. If the valid range consists of just positive integers (e.g., 32 to 100) and \a input is a negative integer, then Invalid is returned. (On the other @@ -380,6 +381,10 @@ QIntValidator::~QIntValidator() the user might be just about to type the minus (especially for right-to-left languages). + Similarly, if the valid range is between 46 and 53, then 41 and 59 will be + evaluated as \l Intermediate, as otherwise the user wouldn't be able to + change a value from 49 to 51. + \snippet code/src_gui_util_qvalidator.cpp 2 By default, the \a pos parameter is not used by this validator. -- cgit v1.2.3 From ab4c22d47d196d5eb28fc16cd7262c77bcb6875f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Fri, 3 Apr 2020 12:45:36 +0200 Subject: macOS: Remove all use of deprecated Q_OS_OSX define Change-Id: I49c285604694c93d37c9d1c7cd6d3b1509858319 Reviewed-by: Volker Hilsheimer --- src/gui/kernel/qguiapplication.cpp | 2 +- src/gui/kernel/qkeysequence.cpp | 2 +- src/gui/kernel/qplatformdialoghelper.cpp | 2 +- src/gui/kernel/qwindowsysteminterface.cpp | 4 ++-- src/gui/opengl/qopengl.cpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src/gui') diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index b9e8db8789..13369dc8f6 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -2320,7 +2320,7 @@ void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyE static bool menuKeyPressAccepted = false; #endif -#if !defined(Q_OS_OSX) +#if !defined(Q_OS_MACOS) // FIXME: Include OS X in this code path by passing the key event through // QPlatformInputContext::filterEvent(). if (e->keyType == QEvent::KeyPress && window) { diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp index 3a3dd42cae..a75b8ef920 100644 --- a/src/gui/kernel/qkeysequence.cpp +++ b/src/gui/kernel/qkeysequence.cpp @@ -1288,7 +1288,7 @@ QString QKeySequencePrivate::encodeString(int key, QKeySequence::SequenceFormat QString p = keyName(key, format); -#if defined(Q_OS_OSX) +#if defined(Q_OS_MACOS) if (nativeText) s += p; else diff --git a/src/gui/kernel/qplatformdialoghelper.cpp b/src/gui/kernel/qplatformdialoghelper.cpp index 5face96575..33cd004234 100644 --- a/src/gui/kernel/qplatformdialoghelper.cpp +++ b/src/gui/kernel/qplatformdialoghelper.cpp @@ -979,7 +979,7 @@ QPlatformDialogHelper::ButtonRole QPlatformDialogHelper::buttonRole(QPlatformDia const int *QPlatformDialogHelper::buttonLayout(Qt::Orientation orientation, ButtonLayout policy) { if (policy == UnknownLayout) { -#if defined (Q_OS_OSX) +#if defined (Q_OS_MACOS) policy = MacLayout; #elif defined (Q_OS_LINUX) || defined (Q_OS_UNIX) policy = KdeLayout; diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index b20578940c..aefb377683 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -498,7 +498,7 @@ QT_DEFINE_QPA_EVENT_HANDLER(bool, handleKeyEvent, QWindow *window, QEvent::Type QT_DEFINE_QPA_EVENT_HANDLER(bool, handleKeyEvent, QWindow *window, ulong timestamp, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text, bool autorep, ushort count) { -#if defined(Q_OS_OSX) +#if defined(Q_OS_MACOS) if (t == QEvent::KeyPress && QWindowSystemInterface::handleShortcutEvent(window, timestamp, k, mods, 0, 0, 0, text, autorep, count)) return true; #endif @@ -526,7 +526,7 @@ bool QWindowSystemInterface::handleExtendedKeyEvent(QWindow *window, ulong times const QString& text, bool autorep, ushort count, bool tryShortcutOverride) { -#if defined(Q_OS_OSX) +#if defined(Q_OS_MACOS) if (tryShortcutOverride && type == QEvent::KeyPress && QWindowSystemInterface::handleShortcutEvent(window, timestamp, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count)) { return true; diff --git a/src/gui/opengl/qopengl.cpp b/src/gui/opengl/qopengl.cpp index adca536797..3066b83282 100644 --- a/src/gui/opengl/qopengl.cpp +++ b/src/gui/opengl/qopengl.cpp @@ -295,7 +295,7 @@ QString OsTypeTerm::hostOs() return QStringLiteral("win"); #elif defined(Q_OS_LINUX) return QStringLiteral("linux"); -#elif defined(Q_OS_OSX) +#elif defined(Q_OS_MACOS) return QStringLiteral("macosx"); #elif defined(Q_OS_ANDROID) return QStringLiteral("android"); -- cgit v1.2.3 From 1c23d34ad4bdd67dec6d501d91087823dc9ea358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Fri, 3 Apr 2020 13:56:26 +0200 Subject: qpa: Remove references to lighthouse Change-Id: I37646113f626c878883cff49f4e186ec71bcfa15 Reviewed-by: Paul Olav Tvete --- src/gui/image/qbmphandler_p.h | 2 +- src/gui/image/qpixmap.cpp | 2 +- src/gui/text/qfontengine.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/gui') diff --git a/src/gui/image/qbmphandler_p.h b/src/gui/image/qbmphandler_p.h index fd044fc442..e1d744e539 100644 --- a/src/gui/image/qbmphandler_p.h +++ b/src/gui/image/qbmphandler_p.h @@ -98,7 +98,7 @@ struct BMP_INFOHDR { // BMP information header // BMP-Handler, which is also able to read and write the DIB // (Device-Independent-Bitmap) format used internally in the Windows operating // system for OLE/clipboard operations. DIB is a subset of BMP (without file -// header). The Windows-Lighthouse plugin accesses the DIB-functionality. +// header). The Windows platform plugin accesses the DIB-functionality. class QBmpHandler : public QImageIOHandler { diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index 269f236ecd..c8db8b2996 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -78,7 +78,7 @@ static bool qt_pixmap_thread_test() if (qApp->thread() != QThread::currentThread()) { bool fail = false; if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedPixmaps)) { - printf("Lighthouse plugin does not support threaded pixmaps!\n"); + printf("Platform plugin does not support threaded pixmaps!\n"); fail = true; } if (fail) { diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index bffe1a10e0..b6046b0fc5 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -2268,7 +2268,7 @@ bool QFontEngineMulti::canRender(const QChar *string, int len) const return true; } -/* Implement alphaMapForGlyph() which is called by Lighthouse/Windows code. +/* Implement alphaMapForGlyph() which is called by QPA Windows code. * Ideally, that code should be fixed to correctly handle QFontEngineMulti. */ QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph) -- cgit v1.2.3 From f9137c8c6ec9174a9b92234bc8b49ee2445798b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Tue, 31 Mar 2020 00:53:41 +0200 Subject: =?UTF-8?q?Wasm:=20don=E2=80=99t=20deadlock=20on=20parallel=20imag?= =?UTF-8?q?e=20conversions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A special restriction of threads on WebAssembly is that you should not block the main thread, also not to wait for worker threads. For example, blocking the main thread may prevent the browser from starting a new web worker to service the pthread the main thread is waiting for. We may be able create an abstraction to support use cases like this (most likely using emscripten asyncify), but for disable use of threads to avoid deadlocking. Change-Id: I35edd5e1bb465e2549fa7cc4288b47dcd2e4244b Reviewed-by: Allan Sandfeld Jensen --- src/gui/image/qimage_conversions.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src/gui') diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index 853bbe4f8e..34d2b8d8c7 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -48,6 +48,11 @@ #if QT_CONFIG(thread) #include #include +#ifdef Q_OS_WASM +// WebAssembly has threads; however we can't block the main thread. +#else +#define QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS +#endif #endif QT_BEGIN_NAMESPACE @@ -227,7 +232,7 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio } }; -#if QT_CONFIG(thread) +#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS int segments = src->nbytes / (1<<16); segments = std::min(segments, src->height); @@ -281,7 +286,7 @@ void convert_generic_to_rgb64(QImageData *dest, const QImageData *src, Qt::Image destData += dest->bytes_per_line; } }; -#if QT_CONFIG(thread) +#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS int segments = src->nbytes / (1<<16); segments = std::min(segments, src->height); @@ -388,7 +393,7 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im destData += params.bytesPerLine; } }; -#if QT_CONFIG(thread) +#ifdef QT_USE_THREAD_PARALLEL_IMAGE_CONVERSIONS int segments = data->nbytes / (1<<16); segments = std::min(segments, data->height); if (segments > 1) { -- cgit v1.2.3