472 QRhiSwapChain *swapchain,
474 qreal sourceDevicePixelRatio,
475 const QRegion ®ion,
476 const QPoint &offset,
477 QPlatformTextureList *textures,
478 bool translucentBackground,
479 qreal sourceTransformFactor)
481 if (!rhi || !swapchain)
482 return QPlatformBackingStore::FlushFailed;
489 if (!sourceTransformFactor)
490 sourceTransformFactor = sourceDevicePixelRatio;
496 }
else if (m_rhi != rhi) {
497 qWarning(
"QBackingStoreDefaultCompositor: the QRhi has changed unexpectedly, this should not happen");
498 return QPlatformBackingStore::FlushFailed;
501 if (!qt_window_private(window)->receivedExpose)
502 return QPlatformBackingStore::FlushSuccess;
504 qCDebug(lcQpaBackingStore) <<
"Composing and flushing" << region <<
"of" << window
505 <<
"at offset" << offset <<
"with" << textures->count() <<
"texture(s) in" << textures
506 <<
"via swapchain" << swapchain;
508 QWindowPrivate::get(window)->lastComposeTime.start();
510 if (swapchain->currentPixelSize() != swapchain->surfacePixelSize()) {
511 if (!swapchain->createOrResize()) {
512 return rhi->isDeviceLost() ? QPlatformBackingStore::FlushFailedDueToLostDevice
513 : QPlatformBackingStore::FlushFailed;
518 QRhi::FrameOpResult frameResult = rhi->beginFrame(swapchain);
519 if (frameResult == QRhi::FrameOpSwapChainOutOfDate) {
520 if (!swapchain->createOrResize())
521 return QPlatformBackingStore::FlushFailed;
522 frameResult = rhi->beginFrame(swapchain);
524 if (frameResult == QRhi::FrameOpDeviceLost)
525 return QPlatformBackingStore::FlushFailedDueToLostDevice;
526 if (frameResult != QRhi::FrameOpSuccess)
527 return QPlatformBackingStore::FlushFailed;
530 QRhiResourceUpdateBatch *resourceUpdates = rhi->nextResourceUpdateBatch();
531 QPlatformBackingStore::TextureFlags flags;
533 const QRegion dirtyRegion = scaledDirtyRegion(region, sourceTransformFactor, offset);
534 bool gotTextureFromGraphicsBuffer =
false;
535 if (QPlatformGraphicsBuffer *graphicsBuffer = backingStore->graphicsBuffer()) {
536 if (graphicsBuffer->lock(QPlatformGraphicsBuffer::SWReadAccess)) {
537 const QImage::Format format = QImage::toImageFormat(graphicsBuffer->format());
538 const QSize size = graphicsBuffer->size();
539 QImage wrapperImage(graphicsBuffer->data(), size.width(), size.height(), graphicsBuffer->bytesPerLine(), format);
540 toTexture(wrapperImage, rhi, resourceUpdates, dirtyRegion, &flags);
541 gotTextureFromGraphicsBuffer =
true;
542 graphicsBuffer->unlock();
543 if (graphicsBuffer->origin() == QPlatformGraphicsBuffer::OriginBottomLeft)
544 flags |= QPlatformBackingStore::TextureFlip;
547 if (!gotTextureFromGraphicsBuffer)
548 toTexture(backingStore, rhi, resourceUpdates, dirtyRegion, &flags);
550 ensureResources(resourceUpdates, swapchain->renderPassDescriptor());
552 UpdateUniformOptions uniformOptions;
553#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
554 if (flags & QPlatformBackingStore::TextureSwizzle)
555 uniformOptions |= NeedsRedBlueSwap;
557 if (flags & QPlatformBackingStore::TextureSwizzle)
558 uniformOptions |= NeedsAlphaRotate;
560 const bool premultiplied = (flags & QPlatformBackingStore::TexturePremultiplied) != 0;
562 if (flags & QPlatformBackingStore::TextureFlip)
565 const qreal dpr = window->devicePixelRatio();
566 const QRect deviceWindowRect = scaledRect(QRect(QPoint(), window->size()), dpr);
567 const QRect sourceWindowRect = scaledRect(QRect(QPoint(), window->size()), sourceDevicePixelRatio);
571 const bool needsLinearSampler = sourceWindowRect.width() > deviceWindowRect.width()
572 && sourceWindowRect.height() > deviceWindowRect.height();
574 const bool invertTargetY = !rhi->isYUpInNDC();
575 const bool invertSource = !rhi->isYUpInFramebuffer();
581 const QPoint sourceWindowOffset = scaledOffset(offset, sourceTransformFactor);
582 const QRect srcRect = toBottomLeftRect(sourceWindowRect.translated(sourceWindowOffset), m_texture->pixelSize().height());
583 const QMatrix3x3 source = sourceTransform(srcRect, m_texture->pixelSize(), origin);
586 target.data()[5] = -1.0f;
587 updateUniforms(&m_widgetQuadData, resourceUpdates, target, source, uniformOptions);
588 if (needsLinearSampler)
589 updatePerQuadData(&m_widgetQuadData, m_texture.get(),
nullptr, NeedsLinearFiltering);
592 const int textureWidgetCount = textures->count();
593 const int oldTextureQuadDataCount = m_textureQuadData.size();
594 if (oldTextureQuadDataCount != textureWidgetCount) {
595 for (
int i = textureWidgetCount; i < oldTextureQuadDataCount; ++i)
596 m_textureQuadData[i].reset();
597 m_textureQuadData.resize(textureWidgetCount);
600 for (
int i = 0; i < textureWidgetCount; ++i) {
601 const bool invertSourceForTextureWidget = textures->flags(i).testFlag(QPlatformTextureList::MirrorVertically)
602 ? !invertSource : invertSource;
605 if (!prepareDrawForRenderToTextureWidget(textures, i, window, deviceWindowRect,
606 offset, invertTargetY, invertSourceForTextureWidget,
609 m_textureQuadData[i].reset();
612 QRhiTexture *t = textures->texture(i);
613 QRhiTexture *tExtra = textures->textureExtra(i);
615 if (!m_textureQuadData[i].isValid())
616 m_textureQuadData[i] = createPerQuadData(t, tExtra);
618 updatePerQuadData(&m_textureQuadData[i], t, tExtra);
619 updateUniforms(&m_textureQuadData[i], resourceUpdates, target, source);
620 if (needsLinearSampler)
621 updatePerQuadData(&m_textureQuadData[i], t, tExtra, NeedsLinearFiltering);
623 m_textureQuadData[i].reset();
628 QRhiCommandBuffer *cb = swapchain->currentFrameCommandBuffer();
629 const QSize outputSizeInPixels = swapchain->currentPixelSize();
630 QColor clearColor = translucentBackground ? Qt::transparent : Qt::black;
632 cb->resourceUpdate(resourceUpdates);
634 auto render = [&](std::optional<QRhiSwapChain::StereoTargetBuffer> buffer = std::nullopt) {
635 QRhiRenderTarget* target =
nullptr;
636 if (buffer.has_value())
637 target = swapchain->currentFrameRenderTarget(buffer.value());
639 target = swapchain->currentFrameRenderTarget();
641 cb->beginPass(target, clearColor, { 1.0f, 0 });
643 cb->setGraphicsPipeline(m_psNoBlend.get());
644 cb->setViewport({ 0, 0,
float(outputSizeInPixels.width()),
float(outputSizeInPixels.height()) });
645 QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf.get(), 0);
646 cb->setVertexInput(0, 1, &vbufBinding);
649 for (
int i = 0; i < textureWidgetCount; ++i) {
650 if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) {
651 if (m_textureQuadData[i].isValid()) {
653 QRhiShaderResourceBindings* srb = m_textureQuadData[i].srb;
654 if (buffer == QRhiSwapChain::RightBuffer && m_textureQuadData[i].srbExtra)
655 srb = m_textureQuadData[i].srbExtra;
657 cb->setShaderResources(srb);
663 cb->setGraphicsPipeline(premultiplied ? m_psPremulBlend.get() : m_psBlend.get());
667 cb->setShaderResources(m_widgetQuadData.srb);
672 for (
int i = 0; i < textureWidgetCount; ++i) {
673 const QPlatformTextureList::Flags flags = textures->flags(i);
674 if (flags.testFlag(QPlatformTextureList::StacksOnTop)) {
675 if (m_textureQuadData[i].isValid()) {
676 if (flags.testFlag(QPlatformTextureList::NeedsPremultipliedAlphaBlending))
677 cb->setGraphicsPipeline(m_psPremulBlend.get());
679 cb->setGraphicsPipeline(m_psBlend.get());
681 QRhiShaderResourceBindings* srb = m_textureQuadData[i].srb;
682 if (buffer == QRhiSwapChain::RightBuffer && m_textureQuadData[i].srbExtra)
683 srb = m_textureQuadData[i].srbExtra;
685 cb->setShaderResources(srb);
694 if (swapchain->window()->format().stereo()) {
695 render(QRhiSwapChain::LeftBuffer);
696 render(QRhiSwapChain::RightBuffer);
700 const QRhi::FrameOpResult endResult = rhi->endFrame(swapchain);
701 if (endResult == QRhi::FrameOpDeviceLost)
702 return QPlatformBackingStore::FlushFailedDueToLostDevice;
703 if (endResult != QRhi::FrameOpSuccess)
704 return QPlatformBackingStore::FlushFailed;
706 return QPlatformBackingStore::FlushSuccess;