275 QRhiShaderResourceBindings *srb,
276 QRhiRenderPassDescriptor *rpDesc,
279 QRhiGraphicsPipeline *ps = rhi->newGraphicsPipeline();
284 QRhiGraphicsPipeline::TargetBlend blend;
286 blend.srcColor = QRhiGraphicsPipeline::SrcAlpha;
287 blend.dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
288 blend.srcAlpha = QRhiGraphicsPipeline::One;
289 blend.dstAlpha = QRhiGraphicsPipeline::One;
290 ps->setTargetBlends({ blend });
295 QRhiGraphicsPipeline::TargetBlend blend;
297 blend.srcColor = QRhiGraphicsPipeline::One;
298 blend.dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
299 blend.srcAlpha = QRhiGraphicsPipeline::One;
300 blend.dstAlpha = QRhiGraphicsPipeline::One;
301 ps->setTargetBlends({ blend });
308 ps->setShaderStages({
309 { QRhiShaderStage::Vertex, getShader(
":/qt-project.org/gui/painting/shaders/backingstorecompose.vert.qsb"_L1) },
310 { QRhiShaderStage::Fragment, getShader(
":/qt-project.org/gui/painting/shaders/backingstorecompose.frag.qsb"_L1) }
313 inputLayout.setBindings({ { 5 *
sizeof(
float) } });
314 inputLayout.setAttributes({
315 { 0, 0, QRhiVertexInputAttribute::Float3, 0 },
316 { 0, 1, QRhiVertexInputAttribute::Float2, quint32(3 *
sizeof(
float)) }
318 ps->setVertexInputLayout(inputLayout);
319 ps->setShaderResourceBindings(srb);
320 ps->setRenderPassDescriptor(rpDesc);
323 qWarning(
"QBackingStoreDefaultCompositor: Failed to build graphics pipeline");
467 QRhiSwapChain *swapchain,
469 qreal sourceDevicePixelRatio,
470 const QRegion ®ion,
471 const QPoint &offset,
472 QPlatformTextureList *textures,
473 bool translucentBackground,
474 qreal sourceTransformFactor)
476 if (!rhi || !swapchain)
477 return QPlatformBackingStore::FlushFailed;
484 if (!sourceTransformFactor)
485 sourceTransformFactor = sourceDevicePixelRatio;
491 }
else if (m_rhi != rhi) {
492 qWarning(
"QBackingStoreDefaultCompositor: the QRhi has changed unexpectedly, this should not happen");
493 return QPlatformBackingStore::FlushFailed;
496 if (!qt_window_private(window)->receivedExpose)
497 return QPlatformBackingStore::FlushSuccess;
499 qCDebug(lcQpaBackingStore) <<
"Composing and flushing" << region <<
"of" << window
500 <<
"at offset" << offset <<
"with" << textures->count() <<
"texture(s) in" << textures
501 <<
"via swapchain" << swapchain;
503 QWindowPrivate::get(window)->lastComposeTime.start();
505 if (swapchain->currentPixelSize() != swapchain->surfacePixelSize())
506 swapchain->createOrResize();
509 QRhi::FrameOpResult frameResult = rhi->beginFrame(swapchain);
510 if (frameResult == QRhi::FrameOpSwapChainOutOfDate) {
511 if (!swapchain->createOrResize())
512 return QPlatformBackingStore::FlushFailed;
513 frameResult = rhi->beginFrame(swapchain);
515 if (frameResult == QRhi::FrameOpDeviceLost)
516 return QPlatformBackingStore::FlushFailedDueToLostDevice;
517 if (frameResult != QRhi::FrameOpSuccess)
518 return QPlatformBackingStore::FlushFailed;
521 QRhiResourceUpdateBatch *resourceUpdates = rhi->nextResourceUpdateBatch();
522 QPlatformBackingStore::TextureFlags flags;
524 const QRegion dirtyRegion = scaledDirtyRegion(region, sourceTransformFactor, offset);
525 bool gotTextureFromGraphicsBuffer =
false;
526 if (QPlatformGraphicsBuffer *graphicsBuffer = backingStore->graphicsBuffer()) {
527 if (graphicsBuffer->lock(QPlatformGraphicsBuffer::SWReadAccess)) {
528 const QImage::Format format = QImage::toImageFormat(graphicsBuffer->format());
529 const QSize size = graphicsBuffer->size();
530 QImage wrapperImage(graphicsBuffer->data(), size.width(), size.height(), graphicsBuffer->bytesPerLine(), format);
531 toTexture(wrapperImage, rhi, resourceUpdates, dirtyRegion, &flags);
532 gotTextureFromGraphicsBuffer =
true;
533 graphicsBuffer->unlock();
534 if (graphicsBuffer->origin() == QPlatformGraphicsBuffer::OriginBottomLeft)
535 flags |= QPlatformBackingStore::TextureFlip;
538 if (!gotTextureFromGraphicsBuffer)
539 toTexture(backingStore, rhi, resourceUpdates, dirtyRegion, &flags);
541 ensureResources(resourceUpdates, swapchain->renderPassDescriptor());
543 UpdateUniformOptions uniformOptions;
544#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
545 if (flags & QPlatformBackingStore::TextureSwizzle)
546 uniformOptions |= NeedsRedBlueSwap;
548 if (flags & QPlatformBackingStore::TextureSwizzle)
549 uniformOptions |= NeedsAlphaRotate;
551 const bool premultiplied = (flags & QPlatformBackingStore::TexturePremultiplied) != 0;
553 if (flags & QPlatformBackingStore::TextureFlip)
556 const qreal dpr = window->devicePixelRatio();
557 const QRect deviceWindowRect = scaledRect(QRect(QPoint(), window->size()), dpr);
558 const QRect sourceWindowRect = scaledRect(QRect(QPoint(), window->size()), sourceDevicePixelRatio);
562 const bool needsLinearSampler = sourceWindowRect.width() > deviceWindowRect.width()
563 && sourceWindowRect.height() > deviceWindowRect.height();
565 const bool invertTargetY = !rhi->isYUpInNDC();
566 const bool invertSource = !rhi->isYUpInFramebuffer();
572 const QPoint sourceWindowOffset = scaledOffset(offset, sourceTransformFactor);
573 const QRect srcRect = toBottomLeftRect(sourceWindowRect.translated(sourceWindowOffset), m_texture->pixelSize().height());
574 const QMatrix3x3 source = sourceTransform(srcRect, m_texture->pixelSize(), origin);
577 target.data()[5] = -1.0f;
578 updateUniforms(&m_widgetQuadData, resourceUpdates, target, source, uniformOptions);
579 if (needsLinearSampler)
580 updatePerQuadData(&m_widgetQuadData, m_texture.get(),
nullptr, NeedsLinearFiltering);
583 const int textureWidgetCount = textures->count();
584 const int oldTextureQuadDataCount = m_textureQuadData.size();
585 if (oldTextureQuadDataCount != textureWidgetCount) {
586 for (
int i = textureWidgetCount; i < oldTextureQuadDataCount; ++i)
587 m_textureQuadData[i].reset();
588 m_textureQuadData.resize(textureWidgetCount);
591 for (
int i = 0; i < textureWidgetCount; ++i) {
592 const bool invertSourceForTextureWidget = textures->flags(i).testFlag(QPlatformTextureList::MirrorVertically)
593 ? !invertSource : invertSource;
596 if (!prepareDrawForRenderToTextureWidget(textures, i, window, deviceWindowRect,
597 offset, invertTargetY, invertSourceForTextureWidget,
600 m_textureQuadData[i].reset();
603 QRhiTexture *t = textures->texture(i);
604 QRhiTexture *tExtra = textures->textureExtra(i);
606 if (!m_textureQuadData[i].isValid())
607 m_textureQuadData[i] = createPerQuadData(t, tExtra);
609 updatePerQuadData(&m_textureQuadData[i], t, tExtra);
610 updateUniforms(&m_textureQuadData[i], resourceUpdates, target, source);
611 if (needsLinearSampler)
612 updatePerQuadData(&m_textureQuadData[i], t, tExtra, NeedsLinearFiltering);
614 m_textureQuadData[i].reset();
619 QRhiCommandBuffer *cb = swapchain->currentFrameCommandBuffer();
620 const QSize outputSizeInPixels = swapchain->currentPixelSize();
621 QColor clearColor = translucentBackground ? Qt::transparent : Qt::black;
623 cb->resourceUpdate(resourceUpdates);
625 auto render = [&](std::optional<QRhiSwapChain::StereoTargetBuffer> buffer = std::nullopt) {
626 QRhiRenderTarget* target =
nullptr;
627 if (buffer.has_value())
628 target = swapchain->currentFrameRenderTarget(buffer.value());
630 target = swapchain->currentFrameRenderTarget();
632 cb->beginPass(target, clearColor, { 1.0f, 0 });
634 cb->setGraphicsPipeline(m_psNoBlend.get());
635 cb->setViewport({ 0, 0,
float(outputSizeInPixels.width()),
float(outputSizeInPixels.height()) });
636 QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf.get(), 0);
637 cb->setVertexInput(0, 1, &vbufBinding);
640 for (
int i = 0; i < textureWidgetCount; ++i) {
641 if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) {
642 if (m_textureQuadData[i].isValid()) {
644 QRhiShaderResourceBindings* srb = m_textureQuadData[i].srb;
645 if (buffer == QRhiSwapChain::RightBuffer && m_textureQuadData[i].srbExtra)
646 srb = m_textureQuadData[i].srbExtra;
648 cb->setShaderResources(srb);
654 cb->setGraphicsPipeline(premultiplied ? m_psPremulBlend.get() : m_psBlend.get());
658 cb->setShaderResources(m_widgetQuadData.srb);
663 for (
int i = 0; i < textureWidgetCount; ++i) {
664 const QPlatformTextureList::Flags flags = textures->flags(i);
665 if (flags.testFlag(QPlatformTextureList::StacksOnTop)) {
666 if (m_textureQuadData[i].isValid()) {
667 if (flags.testFlag(QPlatformTextureList::NeedsPremultipliedAlphaBlending))
668 cb->setGraphicsPipeline(m_psPremulBlend.get());
670 cb->setGraphicsPipeline(m_psBlend.get());
672 QRhiShaderResourceBindings* srb = m_textureQuadData[i].srb;
673 if (buffer == QRhiSwapChain::RightBuffer && m_textureQuadData[i].srbExtra)
674 srb = m_textureQuadData[i].srbExtra;
676 cb->setShaderResources(srb);
685 if (swapchain->window()->format().stereo()) {
686 render(QRhiSwapChain::LeftBuffer);
687 render(QRhiSwapChain::RightBuffer);
691 rhi->endFrame(swapchain);
693 return QPlatformBackingStore::FlushSuccess;