475 QRhiSwapChain *swapchain,
477 qreal sourceDevicePixelRatio,
478 const QRegion ®ion,
479 const QPoint &offset,
480 QPlatformTextureList *textures,
481 bool translucentBackground,
482 qreal sourceTransformFactor)
484 if (!rhi || !swapchain)
485 return QPlatformBackingStore::FlushFailed;
492 if (!sourceTransformFactor)
493 sourceTransformFactor = sourceDevicePixelRatio;
499 }
else if (m_rhi != rhi) {
500 qWarning(
"QBackingStoreDefaultCompositor: the QRhi has changed unexpectedly, this should not happen");
501 return QPlatformBackingStore::FlushFailed;
504 if (!qt_window_private(window)->receivedExpose)
505 return QPlatformBackingStore::FlushSuccess;
507 qCDebug(lcQpaBackingStore) <<
"Composing and flushing" << region <<
"of" << window
508 <<
"at offset" << offset <<
"with" << textures->count() <<
"texture(s) in" << textures
509 <<
"via swapchain" << swapchain;
511 QWindowPrivate::get(window)->lastComposeTime.start();
513 if (swapchain->currentPixelSize() != swapchain->surfacePixelSize()) {
514 if (!swapchain->createOrResize()) {
515 return rhi->isDeviceLost() ? QPlatformBackingStore::FlushFailedDueToLostDevice
516 : QPlatformBackingStore::FlushFailed;
521 QRhi::FrameOpResult frameResult = rhi->beginFrame(swapchain);
522 if (frameResult == QRhi::FrameOpSwapChainOutOfDate) {
523 if (!swapchain->createOrResize())
524 return QPlatformBackingStore::FlushFailed;
525 frameResult = rhi->beginFrame(swapchain);
527 if (frameResult == QRhi::FrameOpDeviceLost)
528 return QPlatformBackingStore::FlushFailedDueToLostDevice;
529 if (frameResult != QRhi::FrameOpSuccess)
530 return QPlatformBackingStore::FlushFailed;
533 QRhiResourceUpdateBatch *resourceUpdates = rhi->nextResourceUpdateBatch();
534 QPlatformBackingStore::TextureFlags flags;
536 const QRegion dirtyRegion = scaledDirtyRegion(region, sourceTransformFactor, offset);
537 bool gotTextureFromGraphicsBuffer =
false;
538 if (QPlatformGraphicsBuffer *graphicsBuffer = backingStore->graphicsBuffer()) {
539 if (graphicsBuffer->lock(QPlatformGraphicsBuffer::SWReadAccess)) {
540 const QImage::Format format = QImage::toImageFormat(graphicsBuffer->format());
541 const QSize size = graphicsBuffer->size();
542 QImage wrapperImage(graphicsBuffer->data(), size.width(), size.height(), graphicsBuffer->bytesPerLine(), format);
543 toTexture(wrapperImage, rhi, resourceUpdates, dirtyRegion, &flags);
544 gotTextureFromGraphicsBuffer =
true;
545 graphicsBuffer->unlock();
546 if (graphicsBuffer->origin() == QPlatformGraphicsBuffer::OriginBottomLeft)
547 flags |= QPlatformBackingStore::TextureFlip;
550 if (!gotTextureFromGraphicsBuffer)
551 toTexture(backingStore, rhi, resourceUpdates, dirtyRegion, &flags);
553 ensureResources(resourceUpdates, swapchain->renderPassDescriptor());
555 UpdateUniformOptions uniformOptions;
556#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
557 if (flags & QPlatformBackingStore::TextureSwizzle)
558 uniformOptions |= NeedsRedBlueSwap;
560 if (flags & QPlatformBackingStore::TextureSwizzle)
561 uniformOptions |= NeedsAlphaRotate;
563 const bool premultiplied = (flags & QPlatformBackingStore::TexturePremultiplied) != 0;
565 if (flags & QPlatformBackingStore::TextureFlip)
568 const qreal dpr = window->devicePixelRatio();
569 const QRect deviceWindowRect = scaledRect(QRect(QPoint(), window->size()), dpr);
570 const QRect sourceWindowRect = scaledRect(QRect(QPoint(), window->size()), sourceDevicePixelRatio);
574 const bool needsLinearSampler = sourceWindowRect.width() > deviceWindowRect.width()
575 && sourceWindowRect.height() > deviceWindowRect.height();
577 const bool invertTargetY = !rhi->isYUpInNDC();
578 const bool invertSource = !rhi->isYUpInFramebuffer();
584 const QPoint sourceWindowOffset = scaledOffset(offset, sourceTransformFactor);
585 const QRect srcRect = toBottomLeftRect(sourceWindowRect.translated(sourceWindowOffset), m_texture->pixelSize().height());
586 const QMatrix3x3 source = sourceTransform(srcRect, m_texture->pixelSize(), origin);
589 target.data()[5] = -1.0f;
590 updateUniforms(&m_widgetQuadData, resourceUpdates, target, source, uniformOptions);
591 if (needsLinearSampler)
592 updatePerQuadData(&m_widgetQuadData, m_texture.get(),
nullptr, NeedsLinearFiltering);
595 const int textureWidgetCount = textures->count();
596 const int oldTextureQuadDataCount = m_textureQuadData.size();
597 if (oldTextureQuadDataCount != textureWidgetCount) {
598 for (
int i = textureWidgetCount; i < oldTextureQuadDataCount; ++i)
599 m_textureQuadData[i].reset();
600 m_textureQuadData.resize(textureWidgetCount);
603 for (
int i = 0; i < textureWidgetCount; ++i) {
604 const bool invertSourceForTextureWidget = textures->flags(i).testFlag(QPlatformTextureList::MirrorVertically)
605 ? !invertSource : invertSource;
608 if (!prepareDrawForRenderToTextureWidget(textures, i, window, deviceWindowRect,
609 offset, invertTargetY, invertSourceForTextureWidget,
612 m_textureQuadData[i].reset();
615 QRhiTexture *t = textures->texture(i);
616 QRhiTexture *tExtra = textures->textureExtra(i);
618 if (!m_textureQuadData[i].isValid())
619 m_textureQuadData[i] = createPerQuadData(t, tExtra);
621 updatePerQuadData(&m_textureQuadData[i], t, tExtra);
622 updateUniforms(&m_textureQuadData[i], resourceUpdates, target, source);
623 if (needsLinearSampler)
624 updatePerQuadData(&m_textureQuadData[i], t, tExtra, NeedsLinearFiltering);
626 m_textureQuadData[i].reset();
631 QRhiCommandBuffer *cb = swapchain->currentFrameCommandBuffer();
632 const QSize outputSizeInPixels = swapchain->currentPixelSize();
633 QColor clearColor = translucentBackground ? Qt::transparent : Qt::black;
635 cb->resourceUpdate(resourceUpdates);
637 auto render = [&](std::optional<QRhiSwapChain::StereoTargetBuffer> buffer = std::nullopt) {
638 QRhiRenderTarget* target =
nullptr;
639 if (buffer.has_value())
640 target = swapchain->currentFrameRenderTarget(buffer.value());
642 target = swapchain->currentFrameRenderTarget();
644 cb->beginPass(target, clearColor, { 1.0f, 0 });
646 cb->setGraphicsPipeline(m_psNoBlend.get());
647 cb->setViewport({ 0, 0,
float(outputSizeInPixels.width()),
float(outputSizeInPixels.height()) });
648 QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf.get(), 0);
649 cb->setVertexInput(0, 1, &vbufBinding);
652 for (
int i = 0; i < textureWidgetCount; ++i) {
653 if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) {
654 if (m_textureQuadData[i].isValid()) {
656 QRhiShaderResourceBindings* srb = m_textureQuadData[i].srb;
657 if (buffer == QRhiSwapChain::RightBuffer && m_textureQuadData[i].srbExtra)
658 srb = m_textureQuadData[i].srbExtra;
660 cb->setShaderResources(srb);
666 cb->setGraphicsPipeline(premultiplied ? m_psPremulBlend.get() : m_psBlend.get());
670 cb->setShaderResources(m_widgetQuadData.srb);
675 for (
int i = 0; i < textureWidgetCount; ++i) {
676 const QPlatformTextureList::Flags flags = textures->flags(i);
677 if (flags.testFlag(QPlatformTextureList::StacksOnTop)) {
678 if (m_textureQuadData[i].isValid()) {
679 if (flags.testFlag(QPlatformTextureList::NeedsPremultipliedAlphaBlending))
680 cb->setGraphicsPipeline(m_psPremulBlend.get());
682 cb->setGraphicsPipeline(m_psBlend.get());
684 QRhiShaderResourceBindings* srb = m_textureQuadData[i].srb;
685 if (buffer == QRhiSwapChain::RightBuffer && m_textureQuadData[i].srbExtra)
686 srb = m_textureQuadData[i].srbExtra;
688 cb->setShaderResources(srb);
697 if (swapchain->window()->format().stereo()) {
698 render(QRhiSwapChain::LeftBuffer);
699 render(QRhiSwapChain::RightBuffer);
703 const QRhi::FrameOpResult endResult = rhi->endFrame(swapchain);
704 if (endResult == QRhi::FrameOpDeviceLost)
705 return QPlatformBackingStore::FlushFailedDueToLostDevice;
706 if (endResult != QRhi::FrameOpSuccess)
707 return QPlatformBackingStore::FlushFailed;
709 return QPlatformBackingStore::FlushSuccess;