282 QRhiShaderResourceBindings *srb,
283 QRhiRenderPassDescriptor *rpDesc,
286 QRhiGraphicsPipeline *ps = rhi->newGraphicsPipeline();
291 QRhiGraphicsPipeline::TargetBlend blend;
293 blend.srcColor = QRhiGraphicsPipeline::SrcAlpha;
294 blend.dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
295 blend.srcAlpha = QRhiGraphicsPipeline::One;
296 blend.dstAlpha = QRhiGraphicsPipeline::One;
297 ps->setTargetBlends({ blend });
302 QRhiGraphicsPipeline::TargetBlend blend;
304 blend.srcColor = QRhiGraphicsPipeline::One;
305 blend.dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
306 blend.srcAlpha = QRhiGraphicsPipeline::One;
307 blend.dstAlpha = QRhiGraphicsPipeline::One;
308 ps->setTargetBlends({ blend });
315 ps->setShaderStages({
316 { QRhiShaderStage::Vertex, getShader(
":/qt-project.org/gui/painting/shaders/backingstorecompose.vert.qsb"_L1) },
317 { QRhiShaderStage::Fragment, getShader(
":/qt-project.org/gui/painting/shaders/backingstorecompose.frag.qsb"_L1) }
320 inputLayout.setBindings({ { 5 *
sizeof(
float) } });
321 inputLayout.setAttributes({
322 { 0, 0, QRhiVertexInputAttribute::Float3, 0 },
323 { 0, 1, QRhiVertexInputAttribute::Float2, quint32(3 *
sizeof(
float)) }
325 ps->setVertexInputLayout(inputLayout);
326 ps->setShaderResourceBindings(srb);
327 ps->setRenderPassDescriptor(rpDesc);
330 qWarning(
"QBackingStoreDefaultCompositor: Failed to build graphics pipeline");
462 QRhiSwapChain *swapchain,
464 qreal sourceDevicePixelRatio,
465 const QRegion ®ion,
466 const QPoint &offset,
467 QPlatformTextureList *textures,
468 bool translucentBackground,
469 qreal sourceTransformFactor)
471 if (!rhi || !swapchain)
472 return QPlatformBackingStore::FlushFailed;
479 if (!sourceTransformFactor)
480 sourceTransformFactor = sourceDevicePixelRatio;
486 }
else if (m_rhi != rhi) {
487 qWarning(
"QBackingStoreDefaultCompositor: the QRhi has changed unexpectedly, this should not happen");
488 return QPlatformBackingStore::FlushFailed;
491 if (!qt_window_private(window)->receivedExpose)
492 return QPlatformBackingStore::FlushSuccess;
494 qCDebug(lcQpaBackingStore) <<
"Composing and flushing" << region <<
"of" << window
495 <<
"at offset" << offset <<
"with" << textures->count() <<
"texture(s) in" << textures
496 <<
"via swapchain" << swapchain;
498 QWindowPrivate::get(window)->lastComposeTime.start();
500 if (swapchain->currentPixelSize() != swapchain->surfacePixelSize())
501 swapchain->createOrResize();
504 QRhi::FrameOpResult frameResult = rhi->beginFrame(swapchain);
505 if (frameResult == QRhi::FrameOpSwapChainOutOfDate) {
506 if (!swapchain->createOrResize())
507 return QPlatformBackingStore::FlushFailed;
508 frameResult = rhi->beginFrame(swapchain);
510 if (frameResult == QRhi::FrameOpDeviceLost)
511 return QPlatformBackingStore::FlushFailedDueToLostDevice;
512 if (frameResult != QRhi::FrameOpSuccess)
513 return QPlatformBackingStore::FlushFailed;
516 QRhiResourceUpdateBatch *resourceUpdates = rhi->nextResourceUpdateBatch();
517 QPlatformBackingStore::TextureFlags flags;
519 const QRegion dirtyRegion = scaledDirtyRegion(region, sourceTransformFactor, offset);
520 bool gotTextureFromGraphicsBuffer =
false;
521 if (QPlatformGraphicsBuffer *graphicsBuffer = backingStore->graphicsBuffer()) {
522 if (graphicsBuffer->lock(QPlatformGraphicsBuffer::SWReadAccess)) {
523 const QImage::Format format = QImage::toImageFormat(graphicsBuffer->format());
524 const QSize size = graphicsBuffer->size();
525 QImage wrapperImage(graphicsBuffer->data(), size.width(), size.height(), graphicsBuffer->bytesPerLine(), format);
526 toTexture(wrapperImage, rhi, resourceUpdates, dirtyRegion, &flags);
527 gotTextureFromGraphicsBuffer =
true;
528 graphicsBuffer->unlock();
529 if (graphicsBuffer->origin() == QPlatformGraphicsBuffer::OriginBottomLeft)
530 flags |= QPlatformBackingStore::TextureFlip;
533 if (!gotTextureFromGraphicsBuffer)
534 toTexture(backingStore, rhi, resourceUpdates, dirtyRegion, &flags);
536 ensureResources(resourceUpdates, swapchain->renderPassDescriptor());
538 UpdateUniformOptions uniformOptions;
539#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
540 if (flags & QPlatformBackingStore::TextureSwizzle)
541 uniformOptions |= NeedsRedBlueSwap;
543 if (flags & QPlatformBackingStore::TextureSwizzle)
544 uniformOptions |= NeedsAlphaRotate;
546 const bool premultiplied = (flags & QPlatformBackingStore::TexturePremultiplied) != 0;
548 if (flags & QPlatformBackingStore::TextureFlip)
551 const qreal dpr = window->devicePixelRatio();
552 const QRect deviceWindowRect = scaledRect(QRect(QPoint(), window->size()), dpr);
553 const QRect sourceWindowRect = scaledRect(QRect(QPoint(), window->size()), sourceDevicePixelRatio);
557 const bool needsLinearSampler = sourceWindowRect.width() > deviceWindowRect.width()
558 && sourceWindowRect.height() > deviceWindowRect.height();
560 const bool invertTargetY = !rhi->isYUpInNDC();
561 const bool invertSource = !rhi->isYUpInFramebuffer();
567 const QPoint sourceWindowOffset = scaledOffset(offset, sourceTransformFactor);
568 const QRect srcRect = toBottomLeftRect(sourceWindowRect.translated(sourceWindowOffset), m_texture->pixelSize().height());
569 const QMatrix3x3 source = sourceTransform(srcRect, m_texture->pixelSize(), origin);
572 target.data()[5] = -1.0f;
573 updateUniforms(&m_widgetQuadData, resourceUpdates, target, source, uniformOptions);
574 if (needsLinearSampler)
575 updatePerQuadData(&m_widgetQuadData, m_texture.get(),
nullptr, NeedsLinearFiltering);
578 const int textureWidgetCount = textures->count();
579 const int oldTextureQuadDataCount = m_textureQuadData.size();
580 if (oldTextureQuadDataCount != textureWidgetCount) {
581 for (
int i = textureWidgetCount; i < oldTextureQuadDataCount; ++i)
582 m_textureQuadData[i].reset();
583 m_textureQuadData.resize(textureWidgetCount);
586 for (
int i = 0; i < textureWidgetCount; ++i) {
587 const bool invertSourceForTextureWidget = textures->flags(i).testFlag(QPlatformTextureList::MirrorVertically)
588 ? !invertSource : invertSource;
591 if (!prepareDrawForRenderToTextureWidget(textures, i, window, deviceWindowRect,
592 offset, invertTargetY, invertSourceForTextureWidget,
595 m_textureQuadData[i].reset();
598 QRhiTexture *t = textures->texture(i);
599 QRhiTexture *tExtra = textures->textureExtra(i);
601 if (!m_textureQuadData[i].isValid())
602 m_textureQuadData[i] = createPerQuadData(t, tExtra);
604 updatePerQuadData(&m_textureQuadData[i], t, tExtra);
605 updateUniforms(&m_textureQuadData[i], resourceUpdates, target, source);
606 if (needsLinearSampler)
607 updatePerQuadData(&m_textureQuadData[i], t, tExtra, NeedsLinearFiltering);
609 m_textureQuadData[i].reset();
614 QRhiCommandBuffer *cb = swapchain->currentFrameCommandBuffer();
615 const QSize outputSizeInPixels = swapchain->currentPixelSize();
616 QColor clearColor = translucentBackground ? Qt::transparent : Qt::black;
618 cb->resourceUpdate(resourceUpdates);
620 auto render = [&](std::optional<QRhiSwapChain::StereoTargetBuffer> buffer = std::nullopt) {
621 QRhiRenderTarget* target =
nullptr;
622 if (buffer.has_value())
623 target = swapchain->currentFrameRenderTarget(buffer.value());
625 target = swapchain->currentFrameRenderTarget();
627 cb->beginPass(target, clearColor, { 1.0f, 0 });
629 cb->setGraphicsPipeline(m_psNoBlend.get());
630 cb->setViewport({ 0, 0,
float(outputSizeInPixels.width()),
float(outputSizeInPixels.height()) });
631 QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf.get(), 0);
632 cb->setVertexInput(0, 1, &vbufBinding);
635 for (
int i = 0; i < textureWidgetCount; ++i) {
636 if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) {
637 if (m_textureQuadData[i].isValid()) {
639 QRhiShaderResourceBindings* srb = m_textureQuadData[i].srb;
640 if (buffer == QRhiSwapChain::RightBuffer && m_textureQuadData[i].srbExtra)
641 srb = m_textureQuadData[i].srbExtra;
643 cb->setShaderResources(srb);
649 cb->setGraphicsPipeline(premultiplied ? m_psPremulBlend.get() : m_psBlend.get());
653 cb->setShaderResources(m_widgetQuadData.srb);
658 for (
int i = 0; i < textureWidgetCount; ++i) {
659 const QPlatformTextureList::Flags flags = textures->flags(i);
660 if (flags.testFlag(QPlatformTextureList::StacksOnTop)) {
661 if (m_textureQuadData[i].isValid()) {
662 if (flags.testFlag(QPlatformTextureList::NeedsPremultipliedAlphaBlending))
663 cb->setGraphicsPipeline(m_psPremulBlend.get());
665 cb->setGraphicsPipeline(m_psBlend.get());
667 QRhiShaderResourceBindings* srb = m_textureQuadData[i].srb;
668 if (buffer == QRhiSwapChain::RightBuffer && m_textureQuadData[i].srbExtra)
669 srb = m_textureQuadData[i].srbExtra;
671 cb->setShaderResources(srb);
680 if (swapchain->window()->format().stereo()) {
681 render(QRhiSwapChain::LeftBuffer);
682 render(QRhiSwapChain::RightBuffer);
686 rhi->endFrame(swapchain);
688 return QPlatformBackingStore::FlushSuccess;