QT 绘画引擎之qtwayland
1 . qt 绘画介绍
QPaintEngine,QPainter,QPaintDevice组成了Qt绘制界面的基础。QPainter为开发者提供外部接口方法用于绘制。QPaintEngine为QPainter提供一些绘制的具体实现 。QPaintDevice为QPainter提供一个绘图设备,用于显示亦或储存。 如果你想使用QPainter绘制自定义的后端(译者注:这里可以理解为QPaintDevice)。你可以继承QPaintEngine,并实现其所有的虚函数。然后子类化QPaintDevice并且实现它的纯虚成员函数(QPaintDevice::paintEngine())。
现在QPaintEngine主要提供的是Qt自带的光栅化引擎(raster engine),Qt在他所有支持的平台上,提供了一个功能完备的光栅化引擎。在Windows, X11 和 macOS平台上,Qt自带的光栅化引擎都是QWidget这个基础类的默认的绘制方法的提供者,亦或是QImage的绘制方法的提供者。当然有一些特殊的绘制设备的绘制引擎不提供对应的绘制方法,这时候就会调用默认的光栅化引擎。当然,我们也为OpenGL(可通过QOpenGLWidget访问)跟打印(允许QPainter在QPrinter对象上绘制,用于生成pdf之类的)也提供了对应的QPaintEngine的实现
find . -name qpaintengine*.cpp
或者你在windows上用everything搜一下
./5.15.2/Src/qtbase/src/gui/image/qpaintengine_pic.cpp
./5.15.2/Src/qtbase/src/gui/painting/qpaintengine.cpp
./5.15.2/Src/qtbase/src/gui/painting/qpaintengineex.cpp
./5.15.2/Src/qtbase/src/gui/painting/qpaintengine_blitter.cpp
./5.15.2/Src/qtbase/src/gui/painting/qpaintengine_raster.cpp
./5.15.2/Src/qtbase/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
./5.15.2/Src/qtbase/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp
./5.15.2/Src/qtbase/src/printsupport/kernel/qpaintengine_alpha.cpp
./5.15.2/Src/qtbase/src/printsupport/kernel/qpaintengine_preview.cpp
这些都是QPaintEngine在各个不同端的派生,有兴趣可以搜下qpaintdevice相关的,也差不多都是这样。比如qpaintengine_raster.cpp 就是Qt自己的光栅化引擎实现,qpaintengine_x11.cpp就是在Linux下默认跟x11交互的光栅化实现。当然并不是所有的派生都会有自己独立的cpp文件,或者叫相关的cpp 。可以对比Qt的官方API来对照下
枚举类型 | 枚举类型 | 描述 |
Constant | Value | Description |
QPaintEngine::X11 | 0 | |
QPaintEngine::Windows | 1 | |
QPaintEngine::MacPrinter | 4 | |
QPaintEngine::CoreGraphics | 3 | macOS的Quartz2D(CoreGraphics) |
QPaintEngine::QWindowSystem | 2 | 嵌入式Linux的Qt |
QPaintEngine::PostScript | 6 | (不再支持) |
QPaintEngine::OpenGL | 7 | |
QPaintEngine::Picture | 8 | QPicture 格式 |
QPaintEngine::SVG | 9 | 可伸缩矢量图形XML格式 |
QPaintEngine::Raster | 10 | |
QPaintEngine::Direct3D | 11 | 仅Windows,基于Direct3D的引擎 |
QPaintEngine::Pdf | 12 | PDF格式 |
QPaintEngine::OpenVG | 13 | |
QPaintEngine::User | 50 | |
QPaintEngine::MaxUser | 100 | |
QPaintEngine::OpenGL2 | 14 | |
QPaintEngine::PaintBuffer | 15 | |
QPaintEngine::Blitter | 16 | |
QPaintEngine::Direct2D | 17 | 仅Windows,基于Direct2D的引擎 |
2. 说下Qt绘制一条线的流程
现在有这样的代码,我们来在Qt中绘制一条线
QLineF line(10.0, 80.0, 90.0, 20.0);QPainter painter(this);
painter.drawLine(line);
如果我们的Qt把渲染引擎设置成了raster引擎,那么qpainter
的实现本质上是调用的QPaintEngine的相关代码。
void QPainter::drawLines(const QLineF *lines, int lineCount)
{
//此处精简代码xxxxxxxxif (lineEmulation) {if (lineEmulation == QPaintEngine::PrimitiveTransform&& d->state->matrix.type() == QTransform::TxTranslate) {for (int i = 0; i < lineCount; ++i) {QLineF line = lines[i];line.translate(d->state->matrix.dx(), d->state->matrix.dy());d->engine->drawLines(&line, 1); //这里调用qpaintengine}} else {QPainterPath linePath;for (int i = 0; i < lineCount; ++i) {linePath.moveTo(lines[i].p1());linePath.lineTo(lines[i].p2());}d->draw_helper(linePath, QPainterPrivate::StrokeDraw); //这里会走模拟绘制本质上也会走一个engine}return;}d->engine->drawLines(lines, lineCount); //或者这里调用qpaintengine
}
那么就调用到了QPaintEngineRaster
的相关实现。QRasterPaintEngine
继承自QPaintEngineEx
,QPaintEngineEx
继承自QPaintEngine
void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
{
#ifdef QT_DEBUG_DRAWqDebug() << " - QRasterPaintEngine::drawLines(QLine*)" << lineCount;
#endifQ_D(QRasterPaintEngine);QRasterPaintEngineState *s = state();ensurePen();if (!s->penData.blend)return;if (s->flags.fast_pen) {QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);for (int i=0; i<lineCount; ++i) {const QLine &l = lines[i];stroker.drawLine(l.p1(), l.p2());}} else {QPaintEngineEx::drawLines(lines, lineCount);}
}
所以QPainter在画画的时候本质上是QPaintEngine提供的方法。
关于QPaintDevice
由QPaintDevice创建QPaintEngine,并维护其生命周期,
上面的代码中,是这样初始化QPainter的。
我们一般重写一个QWidget的paintevent的时候才会这样。
//这里的this实际上就是一个QWidget,QWidget继承自QPaintDevice
QPainter painter(this);
QWidget继承自QPaintDevice,看下源码实现
QWidget::QWidget(QWidgetPrivate &dd, QWidget* parent, Qt::WindowFlags f): QObject(dd, nullptr), QPaintDevice()
QPaintDevice本质上就是一个绘制设备,供我们使用,由于QPaintDevice创建QPaintEngine ,所以QPaintDevice跟QPaintEngine一样,也会有很多种类型的派生。
- QGLFramebufferObject
- QGLPixelBuffer
- QImage,
- QOpenGLPaintDevice,
- QPagedPaintDevice
- QPaintDeviceWindow,
- QPicture
- QPixmap,
- QSvgGenerator
- QWidget
3.QWidget 显示流程:
3.11.update()
void QWidget::update()
{update(rect());
}void QWidget::update(const QRect &rect)
{Q_D(QWidget);d->update(rect);
}template <typename T>
void QWidgetPrivate::update(T r)
{Q_Q(QWidget);if (!q->isVisible() || !q->updatesEnabled())return;T clipped = r & q->rect();if (clipped.isEmpty())return;if (q->testAttribute(Qt::WA_WState_InPaintEvent)) {QCoreApplication::postEvent(q, new QUpdateLaterEvent(clipped));return;}QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();if (tlwExtra && tlwExtra->backingStore)tlwExtra->repaintManager->markDirty(clipped, q);
}void QWidgetRepaintManager::markDirty(const T &r, QWidget *widget, UpdateTime updateTime, BufferState bufferState)
{qCInfo(lcWidgetPainting) << "Marking" << r << "of" << widget << "dirty"<< "with" << updateTime;Q_ASSERT(tlw->d_func()->extra);Q_ASSERT(tlw->d_func()->extra->topextra);Q_ASSERT(widget->isVisible() && widget->updatesEnabled());Q_ASSERT(widget->window() == tlw);Q_ASSERT(!r.isEmpty());
#if QT_CONFIG(graphicseffect)widget->d_func()->invalidateGraphicsEffectsRecursively();
#endifQRect widgetRect = widgetRectFor(widget, r);// ---------------------------------------------------------------------------if (widget->d_func()->shouldPaintOnScreen()) {if (widget->d_func()->dirty.isEmpty()) {widget->d_func()->dirty = r;sendUpdateRequest(widget, updateTime);return;} else if (qt_region_strictContains(widget->d_func()->dirty, widgetRect)) {if (updateTime == UpdateNow)sendUpdateRequest(widget, updateTime);return; // Already dirty}const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty();widget->d_func()->dirty += r;if (!eventAlreadyPosted || updateTime == UpdateNow)sendUpdateRequest(widget, updateTime);return;}// ---------------------------------------------------------------------------if (QWidgetPrivate::get(widget)->renderToTexture) {if (!widget->d_func()->inDirtyList)addDirtyRenderToTextureWidget(widget);if (!updateRequestSent || updateTime == UpdateNow)sendUpdateRequest(tlw, updateTime);return;}// ---------------------------------------------------------------------------QRect effectiveWidgetRect = widget->d_func()->effectiveRectFor(widgetRect);const QPoint offset = widget->mapTo(tlw, QPoint());QRect translatedRect = effectiveWidgetRect.translated(offset);
#if QT_CONFIG(graphicseffect)// Graphics effects may exceed window size, clamptranslatedRect = translatedRect.intersected(QRect(QPoint(), tlw->size()));
#endifif (qt_region_strictContains(dirty, translatedRect)) {if (updateTime == UpdateNow)sendUpdateRequest(tlw, updateTime);return; // Already dirty}// ---------------------------------------------------------------------------if (bufferState == BufferInvalid) {const bool eventAlreadyPosted = !dirty.isEmpty() || updateRequestSent;
#if QT_CONFIG(graphicseffect)if (widget->d_func()->graphicsEffect)dirty += widget->d_func()->effectiveRectFor(r).translated(offset);else
#endifdirty += r.translated(offset);if (!eventAlreadyPosted || updateTime == UpdateNow)sendUpdateRequest(tlw, updateTime);return;}// ---------------------------------------------------------------------------if (dirtyWidgets.isEmpty()) {addDirtyWidget(widget, r);sendUpdateRequest(tlw, updateTime);return;}// ---------------------------------------------------------------------------if (widget->d_func()->inDirtyList) {if (!qt_region_strictContains(widget->d_func()->dirty, effectiveWidgetRect)) {
#if QT_CONFIG(graphicseffect)if (widget->d_func()->graphicsEffect)widget->d_func()->dirty += widget->d_func()->effectiveRectFor(r);else
#endifwidget->d_func()->dirty += r;}} else {addDirtyWidget(widget, r);}// ---------------------------------------------------------------------------if (updateTime == UpdateNow)sendUpdateRequest(tlw, updateTime);
}
template void QWidgetRepaintManager::markDirty<QRect>(const QRect &, QWidget *, UpdateTime, BufferState);
template void QWidgetRepaintManager::markDirty<QRegion>(const QRegion &, QWidget *, UpdateTime, BufferState);
void QWidgetRepaintManager::addDirtyWidget(QWidget *widget, const QRegion &rgn)
{if (widget && !widget->d_func()->inDirtyList && !widget->data->in_destructor) {QWidgetPrivate *widgetPrivate = widget->d_func();
#if QT_CONFIG(graphicseffect)if (widgetPrivate->graphicsEffect)widgetPrivate->dirty = widgetPrivate->effectiveRectFor(rgn.boundingRect());else
#endif // QT_CONFIG(graphicseffect)widgetPrivate->dirty = rgn;dirtyWidgets.append(widget);widgetPrivate->inDirtyList = true;}
}
update()函数并不立即执行刷新。
3.2.void repaint();
void QWidget::repaint()
{repaint(rect());
}void QWidget::repaint(const QRect &rect)
{Q_D(QWidget);d->repaint(rect);
}void QWidgetPrivate::repaint(T r)
{Q_Q(QWidget);if (!q->isVisible() || !q->updatesEnabled() || r.isEmpty())return;QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();if (tlwExtra && tlwExtra->backingStore)tlwExtra->repaintManager->markDirty(r, q, QWidgetRepaintManager::UpdateNow);
}
repaint()函数为立即刷新。
3.3.void scroll(int dx, int dy);
void QWidget::scroll(int dx, int dy)
{if ((!updatesEnabled() && children().size() == 0) || !isVisible())return;if (dx == 0 && dy == 0)return;Q_D(QWidget);
#if QT_CONFIG(graphicsview)if (QGraphicsProxyWidget *proxy = QWidgetPrivate::nearestGraphicsProxyWidget(this)) {// Graphics View maintains its own dirty region as a list of rects;// until we can connect item updates directly to the view, we must// separately add a translated dirty region.for (const QRect &rect : d->dirty)proxy->update(rect.translated(dx, dy));proxy->scroll(dx, dy, proxy->subWidgetRect(this));return;}
#endifd->setDirtyOpaqueRegion();d->scroll_sys(dx, dy);
}void QWidgetPrivate::scroll_sys(int dx, int dy)
{Q_Q(QWidget);scrollChildren(dx, dy);scrollRect(q->rect(), dx, dy);
}void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy)
{Q_Q(QWidget);QWidget *tlw = q->window();QTLWExtra* x = tlw->d_func()->topData();QWidgetRepaintManager *repaintManager = x->repaintManager.get();if (!repaintManager)return;static const bool accelEnv = qEnvironmentVariableIntValue("QT_NO_FAST_SCROLL") == 0;const QRect clipR = clipRect();const QRect scrollRect = rect & clipR;const bool accelerateScroll = accelEnv && isOpaque && !q_func()->testAttribute(Qt::WA_WState_InPaintEvent);if (!accelerateScroll) {if (!overlappedRegion(scrollRect.translated(data.crect.topLeft()), true).isEmpty()) {QRegion region(scrollRect);subtractOpaqueSiblings(region);invalidateBackingStore(region);}else {invalidateBackingStore(scrollRect);}} else {const QPoint toplevelOffset = q->mapTo(tlw, QPoint());const QRect destRect = scrollRect.translated(dx, dy) & scrollRect;const QRect sourceRect = destRect.translated(-dx, -dy);const QRegion overlappedExpose = (overlappedRegion(scrollRect.translated(data.crect.topLeft()))).translated(-data.crect.topLeft()) & clipR;QRegion childExpose(scrollRect);const qreal factor = QHighDpiScaling::factor(q->windowHandle());if (overlappedExpose.isEmpty() || qFloor(factor) == factor) {const QList<QRect> rectsToScroll =getSortedRectsToScroll(QRegion(sourceRect) - overlappedExpose, dx, dy);for (const QRect &r : rectsToScroll) {if (repaintManager->bltRect(r, dx, dy, q)) {childExpose -= r.translated(dx, dy);}}}childExpose -= overlappedExpose;if (inDirtyList) {if (rect == q->rect()) {dirty.translate(dx, dy);} else {QRegion dirtyScrollRegion = dirty.intersected(scrollRect);if (!dirtyScrollRegion.isEmpty()) {dirty -= dirtyScrollRegion;dirtyScrollRegion.translate(dx, dy);dirty += dirtyScrollRegion;}}}if (!q->updatesEnabled())return;if (!overlappedExpose.isEmpty())invalidateBackingStore(overlappedExpose);if (!childExpose.isEmpty()) {repaintManager->markDirty(childExpose, q);isScrolled = true;}// Instead of using native scroll-on-screen, we copy from// backingstore, giving only one screen update for each// scroll, and a solid appearancerepaintManager->markNeedsFlush(q, destRect, toplevelOffset);}
}
3.4 图像数据刷入底层
bool QWidget::event(QEvent *event)
{case QEvent::UpdateRequest:d->syncBackingStore();break;
}void QWidgetPrivate::syncBackingStore()
{if (shouldPaintOnScreen()) {paintOnScreen(dirty);dirty = QRegion();} else if (QWidgetRepaintManager *repaintManager = maybeRepaintManager()) {repaintManager->sync();}
}void QWidgetRepaintManager::sync()
{qCInfo(lcWidgetPainting) << "Syncing dirty widgets";updateRequestSent = false;if (qt_widget_private(tlw)->shouldDiscardSyncRequest()) {// If the top-level is minimized, it's not visible on the screen so we can delay the// update until it's shown again. In order to do that we must keep the dirty states.// These will be cleared when we receive the first expose after showNormal().// However, if the widget is not visible (isVisible() returns false), everything will// be invalidated once the widget is shown again, so clear all dirty states.if (!tlw->isVisible()) {dirty = QRegion();for (int i = 0; i < dirtyWidgets.size(); ++i)resetWidget(dirtyWidgets.at(i));dirtyWidgets.clear();}return;}if (syncAllowed())paintAndFlush();
}void QWidgetRepaintManager::paintAndFlush()
{qCInfo(lcWidgetPainting) << "Painting and flushing dirty"<< "top level" << dirty << "and dirty widgets" << dirtyWidgets;const bool updatesDisabled = !tlw->updatesEnabled();bool repaintAllWidgets = false;const bool inTopLevelResize = tlw->d_func()->maybeTopData()->inTopLevelResize;const QRect tlwRect = tlw->data->crect;const QRect surfaceGeometry(tlwRect.topLeft(), store->size());if ((inTopLevelResize || surfaceGeometry.size() != tlwRect.size()) && !updatesDisabled) {if (hasStaticContents() && !store->size().isEmpty() ) {// Repaint existing dirty area and newly visible area.const QRect clipRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height());const QRegion staticRegion(staticContents(0, clipRect));QRegion newVisible(0, 0, tlwRect.width(), tlwRect.height());newVisible -= staticRegion;dirty += newVisible;store->setStaticContents(staticRegion);} else {// Repaint everything.dirty = QRegion(0, 0, tlwRect.width(), tlwRect.height());for (int i = 0; i < dirtyWidgets.size(); ++i)resetWidget(dirtyWidgets.at(i));dirtyWidgets.clear();repaintAllWidgets = true;}}if (inTopLevelResize || surfaceGeometry.size() != tlwRect.size())store->resize(tlwRect.size());if (updatesDisabled)return;// Contains everything that needs repaint.QRegion toClean(dirty);// Loop through all update() widgets and remove them from the list before they are// painted (in case someone calls update() in paintEvent). If the widget is opaque// and does not have transparent overlapping siblings, append it to the// opaqueNonOverlappedWidgets list and paint it directly without composition.QVarLengthArray<QWidget *, 32> opaqueNonOverlappedWidgets;for (int i = 0; i < dirtyWidgets.size(); ++i) {QWidget *w = dirtyWidgets.at(i);QWidgetPrivate *wd = w->d_func();if (wd->data.in_destructor)continue;// Clip with mask() and clipRect().wd->dirty &= wd->clipRect();wd->clipToEffectiveMask(wd->dirty);// Subtract opaque siblings and children.bool hasDirtySiblingsAbove = false;// We know for sure that the widget isn't overlapped if 'isMoved' is true.if (!wd->isMoved)wd->subtractOpaqueSiblings(wd->dirty, &hasDirtySiblingsAbove);// Make a copy of the widget's dirty region, to restore it in case there is an opaque// render-to-texture child that completely covers the widget, because otherwise the// render-to-texture child won't be visible, due to its parent widget not being redrawn// with a proper blending mask.const QRegion dirtyBeforeSubtractedOpaqueChildren = wd->dirty;// Scrolled and moved widgets must draw all children.if (!wd->isScrolled && !wd->isMoved)wd->subtractOpaqueChildren(wd->dirty, w->rect());if (wd->dirty.isEmpty() && wd->textureChildSeen)wd->dirty = dirtyBeforeSubtractedOpaqueChildren;if (wd->dirty.isEmpty()) {resetWidget(w);continue;}const QRegion widgetDirty(w != tlw ? wd->dirty.translated(w->mapTo(tlw, QPoint())): wd->dirty);toClean += widgetDirty;#if QT_CONFIG(graphicsview)if (tlw->d_func()->extra->proxyWidget) {resetWidget(w);continue;}
#endifif (!hasDirtySiblingsAbove && wd->isOpaque && !dirty.intersects(widgetDirty.boundingRect())) {opaqueNonOverlappedWidgets.append(w);} else {resetWidget(w);dirty += widgetDirty;}}dirtyWidgets.clear();#ifndef QT_NO_OPENGL// Find all render-to-texture child widgets (including self).// The search is cut at native widget boundaries, meaning that each native child widget// has its own list for the subtree below it.QTLWExtra *tlwExtra = tlw->d_func()->topData();tlwExtra->widgetTextures.clear();findAllTextureWidgetsRecursively(tlw, tlw);qt_window_private(tlw->windowHandle())->compositing = false; // will get updated in flush()
#endifif (toClean.isEmpty()) {// Nothing to repaint. However renderToTexture widgets are handled// specially, they are not in the regular dirty list, in order to// prevent triggering unnecessary backingstore painting when only the// OpenGL content changes. Check if we have such widgets in the special// dirty list.QVarLengthArray<QWidget *, 16> paintPending;const int numPaintPending = dirtyRenderToTextureWidgets.count();paintPending.reserve(numPaintPending);for (int i = 0; i < numPaintPending; ++i) {QWidget *w = dirtyRenderToTextureWidgets.at(i);paintPending << w;resetWidget(w);}dirtyRenderToTextureWidgets.clear();for (int i = 0; i < numPaintPending; ++i) {QWidget *w = paintPending[i];w->d_func()->sendPaintEvent(w->rect());if (w != tlw) {QWidget *npw = w->nativeParentWidget();if (hasPlatformWindow(w) || (npw && npw != tlw)) {if (!hasPlatformWindow(w))w = npw;markNeedsFlush(w);}}}// We might have newly exposed areas on the screen if this function was// called from sync(QWidget *, QRegion)), so we have to make sure those// are flushed. We also need to composite the renderToTexture widgets.flush();return;}#ifndef QT_NO_OPENGLfor (const auto &tl : tlwExtra->widgetTextures) {for (int i = 0; i < tl->count(); ++i) {QWidget *w = static_cast<QWidget *>(tl->source(i));if (dirtyRenderToTextureWidgets.contains(w)) {const QRect rect = tl->geometry(i); // mapped to the tlw already// Set a flag to indicate that the paint event for this// render-to-texture widget must not to be optimized away.w->d_func()->renderToTextureReallyDirty = 1;dirty += rect;toClean += rect;}}}for (int i = 0; i < dirtyRenderToTextureWidgets.count(); ++i)resetWidget(dirtyRenderToTextureWidgets.at(i));dirtyRenderToTextureWidgets.clear();
#endif#if QT_CONFIG(graphicsview)if (tlw->d_func()->extra->proxyWidget) {updateStaticContentsSize();dirty = QRegion();updateRequestSent = false;for (const QRect &rect : toClean)tlw->d_func()->extra->proxyWidget->update(rect);return;}
#endifstore->beginPaint(toClean);// Must do this before sending any paint events because// the size may change in the paint event.updateStaticContentsSize();const QRegion dirtyCopy(dirty);dirty = QRegion();updateRequestSent = false;// Paint opaque non overlapped widgets.for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) {QWidget *w = opaqueNonOverlappedWidgets[i];QWidgetPrivate *wd = w->d_func();QWidgetPrivate::DrawWidgetFlags flags = QWidgetPrivate::DrawRecursive;// Scrolled and moved widgets must draw all children.if (!wd->isScrolled && !wd->isMoved)flags |= QWidgetPrivate::DontDrawOpaqueChildren;if (w == tlw)flags |= QWidgetPrivate::DrawAsRoot;QRegion toBePainted(wd->dirty);resetWidget(w);QPoint offset;if (w != tlw)offset += w->mapTo(tlw, QPoint());wd->drawWidget(store->paintDevice(), toBePainted, offset, flags, 0, this);}// Paint the rest with composition.if (repaintAllWidgets || !dirtyCopy.isEmpty()) {QWidgetPrivate::DrawWidgetFlags flags = QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawRecursive;tlw->d_func()->drawWidget(store->paintDevice(), dirtyCopy, QPoint(), flags, 0, this);}store->endPaint();flush();
}
store->beginPaint(toClean);
store->endPaint();
void QBackingStore::beginPaint(const QRegion ®ion)
{if (d_ptr->highDpiBackingstore &&d_ptr->highDpiBackingstore->devicePixelRatio() != d_ptr->window->devicePixelRatio())resize(size());QPlatformBackingStore *platformBackingStore = handle();platformBackingStore->beginPaint(QHighDpi::toNativeLocalRegion(region, d_ptr->window));// When QtGui is applying a high-dpi scale factor the backing store// creates a "large" backing store image. This image needs to be// painted on as a high-dpi image, which is done by setting// devicePixelRatio. Do this on a separate image instance that shares// the image data to avoid having the new devicePixelRatio be propagated// back to the platform plugin.QPaintDevice *device = platformBackingStore->paintDevice();if (QHighDpiScaling::isActive() && device->devType() == QInternal::Image) {QImage *source = static_cast<QImage *>(device);const bool needsNewImage = d_ptr->highDpiBackingstore.isNull()|| source->data_ptr() != d_ptr->highDpiBackingstore->data_ptr()|| source->size() != d_ptr->highDpiBackingstore->size()|| source->devicePixelRatio() != d_ptr->highDpiBackingstore->devicePixelRatio();if (needsNewImage) {qCDebug(lcScaling) << "QBackingStore::beginPaint new backingstore for" << d_ptr->window;qCDebug(lcScaling) << " source size" << source->size() << "dpr" << source->devicePixelRatio();d_ptr->highDpiBackingstore.reset(new QImage(source->bits(), source->width(), source->height(), source->bytesPerLine(), source->format()));qreal targetDevicePixelRatio = d_ptr->window->devicePixelRatio();d_ptr->highDpiBackingstore->setDevicePixelRatio(targetDevicePixelRatio);qCDebug(lcScaling) <<" destination size" << d_ptr->highDpiBackingstore->size()<< "dpr" << targetDevicePixelRatio;}}
}void QBackingStore::endPaint()
{if (paintDevice()->paintingActive())qWarning("QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?");handle()->endPaint();
}
QBackingStore 调用 QPlatformBackingStore 类。QPlatformBackingStore 是QPA 接口,由个backend 实现。
4 .QT wayland 实现QPlatformBackingStore 接口,将绘图数据提交到shm 中。
void QWaylandShmBackingStore::beginPaint(const QRegion ®ion)
{mPainting = true;ensureSize();waylandWindow()->setCanResize(false);if (mBackBuffer->image()->hasAlphaChannel()) {QPainter p(paintDevice());p.setCompositionMode(QPainter::CompositionMode_Source);const QColor blank = Qt::transparent;for (const QRect &rect : region)p.fillRect(rect, blank);}
}void QWaylandShmBackingStore::endPaint()
{mPainting = false;if (mPendingFlush)flush(window(), mPendingRegion, QPoint());waylandWindow()->setCanResize(true);
}void QWaylandShmBackingStore::ensureSize()
{waylandWindow()->setBackingStore(this);waylandWindow()->createDecoration();resize(mRequestedSize);
}void QWaylandShmBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset)
{// Invoked when the window is of type RasterSurface or when the window is// RasterGLSurface and there are no child widgets requiring OpenGL composition.// For the case of RasterGLSurface + having to compose, the composeAndFlush() is// called instead. The default implementation from QPlatformBackingStore is sufficient// however so no need to reimplement that.Q_UNUSED(window);Q_UNUSED(offset);if (mPainting) {mPendingRegion |= region;mPendingFlush = true;return;}mPendingFlush = false;mPendingRegion = QRegion();if (windowDecoration() && windowDecoration()->isDirty())updateDecorations();mFrontBuffer = mBackBuffer;QMargins margins = windowDecorationMargins();waylandWindow()->safeCommit(mFrontBuffer, region.translated(margins.left(), margins.top()));
}
QT 绘画引擎之qtwayland相关推荐
- qt绘画扇形drawPie()和反着三角函数qAcos()
简介: qt绘画扇形drawPie(),绘画出弧线: 和由三角形的长度计算出角度,利用反三角函数qAcos() 文章目录 同步博文: 问题背景: 解决方法: 绘画扇形drawPie(): 反三角计算角 ...
- Qt 绘画小软件(功能完善,免费下载)
Qt 绘画小软件(功能完善,免费下载) 源码下载 免费下载,看评论 操作说明 快捷键 Ctrl + C 复制选中区域快捷键 Ctrl + V 粘贴选中区域快捷键 Ctrl + X 剪切选中区域快捷键 ...
- qt绘画事件-设置背景图片
前言 设置widget的背景图片,并在背景图片上放置别的图片 直接上代码: 头文件 void paintEvent(QPaintEvent *); cpp文件: void MainWindow::pa ...
- 零基础入门 Stable Diffusion - 无需显卡把 AI 绘画引擎搬进家用电脑
我从小特别羡慕会画画的伙伴.他们能够将心中的想法画出来,而我最高水平的肖像画是丁老头.但在接触 Stable Diffusion 之后,我感觉自己脱胎换骨,给自己贴上了「会画画」的新标签. 丁老头进化 ...
- 【Qt象棋游戏】02_绘画象棋棋盘
文章目录 01 - 相关成员与方法 02 - 棋盘颜色 03 - 绘画棋盘线 04 - 添加"井"字格 05 - 总结 01 - 相关成员与方法 进行代码编写之前,在chess ...
- Qt实现Word文档界面样式--QtitanRibbon
QtitanRibbon - Microsoft Ribbon for Nokia's Qt概念的实现 QtitanRibbon组件实现了Microsoft Ribbon for Qt的概念,设计用于 ...
- 绘画系统(02):【纲】Paint Devices and Backends[官翻]
绘画设备和后端 Paint Devices and Backends 创建绘画设备 QPaintDevice类是可以绘制的对象的基类,即QPainter可以在任何QPaintDevice子类上绘制 ...
- Qt 与 Qt Creator 简介
该文章原创于Qter开源社区(www.qter.org),作者 yafeilinux,转载请注明出处! 一.Qt 与 Qt Creator 简介 Qt 是一个跨平台应用程序和 UI 开发框架.使用 Q ...
- 【Qt】QPaintDevice类详解
00. 目录 文章目录 00. 目录 01. 概述 02. 绘制设备参数的指标 03. 成员方法 04. 预留 05. 预留 06. 附录 01. 概述 绘画设备是二维空间的抽象,可以使用QPaint ...
最新文章
- js中常用的对象—String的属性和方法
- 学猫叫用计算机歌词,我们一起学猫叫什么歌歌词是什么意思
- 台式计算机风扇一直响,风扇一直响的原因是什么? 处理方法
- PyTorch Upsample() 函数实现上采样
- MYSQL二级表的管理_MySQL库和表的管理
- 模型开发-GBDT决策树模型开发代码
- goods.java_javaweb网上书城项目 1.用户管理:注册会员 - 下载 - 搜珍网
- Vijos——T 1629 八
- oracle中查询某张表的大小
- html5+中奖结果页面,html5+css3实现抽奖活动的效果
- Python数据可视化案例二:动态更新数据
- python面向对象(其二)
- C# 滑块长度确认 Scrollbar滑块长度问题 水平垂直滚动条滑块高度宽度问题
- Python设计模式:适配器模式
- win10系统realtek高清晰音频管理器有什么用
- JS判断数组是否相同
- qq连连看看外挂-我的QQ连连看“辅助”程序源码
- 中国行政区划编码-省市县镇村
- 支付宝门店码,全面助力商家快速实现数字化经营
- 投递邮件简历要注意的细节
热门文章
- sharepoint2007就地升级2010系列(四)升级数据库
- 服务器水厂物资管理系统,基于B/S的水厂管理信息系统的设计与实现
- 2017第八届蓝桥杯省赛JAVA C组真题解析(带源码及解析)
- QQ空间打不开怎么办
- jQuery(一)jQuery概述、使用方式、原理、查找元素
- 齐岳离子液体[C1MIm]SbF6/cas:885624-41-9/1,3-二甲基咪唑六氟锑酸盐/分子式:C5H9F6N2Sb
- html特殊字符PPT,HTML 文档的结构,标签,在 HTML 文档中插入特殊字符,创建超级链接.ppt...
- 一下科技秒拍升级:打造更符合市场的短视频平台
- 现代家用计算机有哪些名称大全,当前个人计算机(电脑)有哪些形式
- 银行业务管理软件(7)